A UI component common in many applications (and starting to become common on the web as well) is the accordion menu. A number of javascript libraries provide nice and simple accordion menus, but today we are going to take a look at how to build our own - because, well, that is what we do here at Switch On The Code!
Below, you can see the example that we are going to build today. It is a pretty simple animated accordion, where each menu is collapsible/expandable. You can have them all collapsed, or a single menu open. It should be pretty self-explanatory, so play around!

Ok, now that your done having fun with that example, lets take a look at how we actually do this. First, we have the html:
<div id="AccordionContainer" class="AccordionContainer">
<div onclick="runAccordion(1);">
<div class="AccordionTitle" onselectstart="return false;">
Accordion 1
</div>
</div>
<div id="Accordion1Content" class="AccordionContent">
I Am Accordion 1.
</div>
<div onclick="runAccordion(2);">
<div class="AccordionTitle" onselectstart="return false;">
Accordion 2
</div>
</div>
<div id="Accordion2Content" class="AccordionContent">
I Am Accordion 2.
</div>
<div onclick="runAccordion(3);">
<div class="AccordionTitle" onselectstart="return false;">
Accordion 3
</div>
</div>
<div id="Accordion3Content" class="AccordionContent">
I Am Accordion 3.
</div>
<div onclick="runAccordion(4);">
<div class="AccordionTitle" onselectstart="return false;">
Accordion 4
</div>
</div>
<div id="Accordion4Content" class="AccordionContent">
I Am Accordion 4.
</div>
<div onclick="runAccordion(5);">
<div class="AccordionTitle" onselectstart="return false;">
Accordion 5
</div>
</div>
<div id="Accordion5Content" class="AccordionContent">
I Am Accordion 5.
</div>
</div>
Essentially, we have an accordion container div, which holds each of the the accordion menus. Each menu is made up of a title div, and a content div. The title divs have an onclick attachment, which calls the javascript function runAccordion. As you can see, it takes one argument, which represents which menu was actually clicked on (in this case, the menus 1-5). Of course, this doesn make a whole lot of sense unless we define the CSS classes referred to in this html:
.AccordionTitle, .AccordionContent, .AccordionContainer
{
position:relative;
width:200px;
}
.AccordionTitle
{
height:20px;
overflow:hidden;
cursor:pointer;
font-family:Arial;
font-size:8pt;
font-weight:bold;
vertical-align:middle;
text-align:center;
background-repeat:repeat-x;
display:table-cell;
background-image:url( itle_repeater.jpg);
-moz-user-select:none;
}
.AccordionContent
{
height:0px;
overflow:auto;
display:none;
}
.AccordionContainer
{
border-top: solid 1px #C1C1C1;
border-bottom: solid 1px #C1C1C1;
border-left: solid 2px #C1C1C1;
border-right: solid 2px #C1C1C1;
}
So the first chunk of css here applies to everything in the accordion. And it is here that you would change the width - modifying that value changes the entire accordion. Next, we have the style for the title blocks. A lot of stuff here, most of which is just making it look pretty. We use display:table-cell so that the vertical-align:middle style works (which is what aligns the title text in the center vertically). The -moz-user-select:none is to keep the text of the title from getting selected (in Firefox), which is useful because people will be clicking on the title bar. If you don have that option, the title text will often get accidentally selected. The counterpart to this style for IE is the onselectstart="return false;" that we had up above in the html for each of the title divs.
The AccordionContent style is next, and is pretty simple. We hide it and give it a height of 0 pixels, because by default all AccordionContent divs are not displayed. We also set overflow equal to auto, which allows scroll bars to appear when the content is to big for the content div (useful for when the accordion menu is expanded, but the content still does not fit).
Finally, we have the AccordionContainer style, and all that does is set some borders, again mostly to make the menu look pretty.
Now, we can move onto the javascript, which is actually not that complicated. First, we have that runAccordion function referred to above, and some global variables:
var ContentHeight = 200;
var TimeToSlide = 250.0;
var openAccordion = ;
function runAccordion(index)
{
var nID = "Accordion" + index + "Content";
if(openAccordion == nID)
nID = ;
setTimeout("animate("
+ new Date().getTime() + "," + TimeToSlide + ","
+ openAccordion + "," + nID + ")", 33);
openAccordion = nID;
}
So first we have a couple global variables. ContentHeight controls how tall a menu gets when opened - currently it is set to 200 pixels. TimeToSlide is the amount of time for the opening/closing animation, and it is currently set to 250 milliseconds. The opentAccordion variable holds the element id of the current open accordion menu. When there are none open, it is the empty string.
Now for the function runAccordion. The first thing we do here is transform the menu index passed in into the full element id, and hold it in the variable nID. If this is the currently open menu, then we are going to close it, and so nID gets set to the empty string (i.e., there is no new menu to open). The next thing we do is a setTimeout on a call to animate - a function which we will take a look at in a moment. And finally, we set the global openAccordion to the new open accordion, nID.
And here we have the animate function:
function animate(lastTick, timeLeft, closingId, openingId)
{
var curTick = new Date().getTime();
var elapsedTicks = curTick - lastTick;
var opening = (openingId == ) ?
null : document.getElementById(openingId);
var closing = (closingId == ) ?
null : document.getElementById(closingId);
if(timeLeft <= elapsedTicks)
{
if(opening != null)
opening.style.height = ContentHeight + px;
if(closing != null)
{
closing.style.display =
one;
closing.style.height = px;
}
return;
}
timeLeft -= elapsedTicks;
var newClosedHeight =
Math.round((timeLeft/TimeToSlide) * ContentHeight);
if(opening != null)
{
if(opening.style.display != lock)
opening.style.display = lock;
opening.style.height =
(ContentHeight - newClosedHeight) + px;
}
if(closing != null)
closing.style.height = newClosedHeight + px;
setTimeout("animate(" + curTick + "," + timeLeft + ","
+ closingId + "," + openingId + ")", 33);
}
So the animate function takes 4 arguments - the last time the animation was updated, the amount of time left before the animation should complete, the element id of the closing menu, and the element id of the opening menu. The reason we care about time here is that the code always makes sure the animation completes in the amount of time specified in TimeToSlide. If we didn do that, on slow computers the slide would have the potential to take much longer than TimeToSlide.
Because of all that, the first thing we do in the animation function is figure out how much time has passed since the last animation iteration. If that amount of time is greater than (or equal to) the amount of time left in the animation (as specified in timeLeft), we finish the animation. We do this by setting the opening menu (if there is an opening menu) to its full size, setting the size of the closing menu (if there is one) to 0 and making it invisible, and then returning out, thereby ending the animation.
If there is still time left in the animation, we calculate the ratio of time left to the total time in the animation, and multiply it by the the full menu height. This returns the new value for the height of the closing menu. Now, if there is a menu we are opening, we first make sure it is visible (because closed menus are initially invisible), and if it isn we make it visible. Next we set the new height, which is full menu height minus the new height of the closing menu (this way as one menu closes, the other opens exactly in sync). Then, if there is a menu we are closing, we set its new height.
Finally, we do a new setTimeout call to animate, with the new values for the last time the animation was updated and the amount of time left in the animation.
And that is all that is needed to create an animated accordion menu using css and javascript! Here is a link to the javascript source file, and if you have any question or comments, feel free to leave them below.
source: blog.paranoidferret
Related Stuff
-
MooV: Using cutting edge Video phones and Software Video Phones - coupling all that with VoIP and empowering the disabled.
-
Moo Telecom: VoIP communications made easy - Ring anyway with the fun and ease of using a normal phone
-
TagR:Mobile Social Network with Real Time Locations Based services, and Ambience Intelligence, VoiP, IM, Skype, Googletalk, Mapping, Flickr, Events, Calendaring, Scheduling, SecondLife Support
-
ClearSMS : ClearSMS is a Web-based application that lets you send bulk SMS messages to your customers, contacts, or just about anyone.
-
Jajah:jah is a VoIP (Voice over IP) provider, founded by Austrians Roman Scharf and Daniel Mattes in 2005[1]. The Jajah headquarters are located in Mountain View, CA, USA, and Luxembourg. Jajah maintains a development centre in Israel.
-
Skype: It’s free to download and free to call other people on Skype. Skype the number one voice over ip software
- PrivatePhone: a free local phone number with voicemail and messages you can check online or from any phone.

