Javascript And CSS Tutorial - Accordion Menus
| 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! |
Accordion 1
I Am Accordion 1.
Accordion 2
I Am Accordion 2.
Accordion 3
I Am Accordion 3.
Accordion 4
I Am Accordion 4.
Accordion 5
I Am Accordion 5.
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>
<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't 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('title_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;
}
{
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('title_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't 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;
}
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 = 'none';
closing.style.height = '0px';
}
return;
}
timeLeft -= elapsedTicks;
var newClosedHeight =
Math.round((timeLeft/TimeToSlide) * ContentHeight);
if(opening != null)
{
if(opening.style.display != 'block')
opening.style.display = 'block';
opening.style.height =
(ContentHeight - newClosedHeight) + 'px';
}
if(closing != null)
closing.style.height = newClosedHeight + 'px';
setTimeout("animate(" + curTick + "," + timeLeft + ",'"
+ closingId + "','" + openingId + "')", 33);
}
{
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 = 'none';
closing.style.height = '0px';
}
return;
}
timeLeft -= elapsedTicks;
var newClosedHeight =
Math.round((timeLeft/TimeToSlide) * ContentHeight);
if(opening != null)
{
if(opening.style.display != 'block')
opening.style.display = 'block';
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't 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't 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.
Posted in CSS, Javascript, All Tutorials by The Tallest |
88 Responses
Tracebacks / Pingbacks
-
hosthg » Blog Archive » Javascript And CSS Tutorial - Accordion Menus
October 22nd, 2007 at 11:35 am -
echo20 » Blog Archive » Javascript And CSS Tutorial - Accordion Menus
October 22nd, 2007 at 1:22 pm -
nookli » Blog Archive » Javascript And CSS Tutorial - Accordion Menus
October 22nd, 2007 at 1:49 pm

November 2nd, 2007 at 10:22 am
Is there anyway to get one of the accordians to Start opened up? I would like to make this be a type of a front page news story viewer.
November 19th, 2007 at 5:19 am
Here is good tutorial about CSS :http://gohil.dharmesh.googlepages.com/css.html
Here is good tutorial about AJAX :http://gohil.dharmesh.googlepages.com/ajax.html
December 4th, 2007 at 11:39 am
Nick, to have accordion 1 open by default, add this class to your css:
.AccordionOpen
{
height:200px;
overflow:auto;
}
and then alter the Accordion 1 html to represent this new class:
I Am Accordion 1.
December 4th, 2007 at 11:41 am
oops, just change the class in the div that surrounds the text “I am Accordion 1.” from AccordionContent to AccordionOpen
December 6th, 2007 at 6:55 am
Hi, how to do it without a height specified? Thanks.
December 6th, 2007 at 9:44 pm
Hi there,
Nice control.
I noticed that when opened the height of the opened area is fixed. How does one make the area dynamically high depending on the content.
Also I made my own image & the text within the image gets chopped off - any ideas on how to control this ?
Thanks Dave
December 7th, 2007 at 9:02 am
I hadn’t checked on the comments on this tutorial in a while, and I see there are a lot of “feature requests”
In the next week or so, I’ll try and put together a more advanced accordion control that accommodates everyone’s requests - so look for an article in the near future!
December 9th, 2007 at 6:10 pm
Awesome script!!
I’m looking forward to reading your next tutorial for the dynamic height control.
Also, I don’t like how it shows the scroll bar when it opens up, can that be removed?
Thanks
Happy coding…
December 11th, 2007 at 1:26 am
Thanks so very much for the terrific script. Not only do you provide it, but you explain what you did, how, and why. Very well done. If you want to see what I did with it (a little BSP here), visit www.mysteriesontv.com. I found that initially visitors to the site didn’t understand how the menu worked despite a brief statement telling them what to do. After I modified the procedure a bit and displayed the first three entries of each category, people seemed to understand better. It’s definitely an improvement over the list of over 100 titles I previously had listed there! Anyway, thanks again!
December 11th, 2007 at 4:21 pm
In response to Dave Porter:
“I noticed that when opened the height of the opened area is fixed. How does one make the area dynamically high depending on the content.”
I needed the same functionality but couldn’t find a way to allow AccordionContent to expand that div, but I did find a way to override the ContentHeight variable in the js file by turning it off, and then create a height in a style sheet for each Accordion#Content div. It works, though I’m sure the developer can provide a more elegant solution. I’m showing changed parts only. Essentially, the changes are just commenting out the parts of the script that use the ContentHeight var.
———
Change 1:
var ContentHeight = ”;
———————–
Change 2:
if(timeLeft
December 11th, 2007 at 4:22 pm
Woops. Not sure if I can post the length of code I did or whether it is in moderation. I’ll check back and repost or post a link.
TS
December 13th, 2007 at 7:44 am
Very nice script, well explained, thanks for sharing such expirience.
I noticed, or believe so (correct me if I am wrong) that maybe ,just incase the computer is sooo slow that if it enters in the animate rountine for the first time past 250 ms already.
The display condition should be checked aswell in the first if:
if(timeLeft
December 13th, 2007 at 7:51 am
The display condition should be checked aswell in the first if:
if(timeLeft
December 13th, 2007 at 7:55 am
Ok, Sorry for having here 3 posts, but the closed crocadile mouth and the equal sign.. somehow end the post.
….
the display condition should be checked otherwise maybe the new open element might remain hidden.
Any ideas on how to make an evolution of this to a circular accordion? or an approximation for example a pentagonal design?
Cheers, Pau
December 20th, 2007 at 1:09 am
I am using accordion but it is working fine in IE7 but does not displays the div contents for the first title in Mozila unless I select other than first title option.After that if again first option is selected, it diplays the div contents.
I face this problem only in Firefox.
December 26th, 2007 at 2:00 pm
Hi, thanks for the great tutorial! It works great. I would like for the first accordion to be open as a default. I tried Julio’s suggestion above and even though it does work, the accordion then stays open even when you click on the others. Is there a fix for that?
Again, thank you!
LM
January 10th, 2008 at 10:12 am
Great tutorial!
Quick question.
Is there a way to add a link on the top level (i.e Accordion 1) so that it goes to a sub page while opening the I am Accordion 1 submenu on the sub page?
January 10th, 2008 at 11:04 am
Here is how I adjusted the sizing for the accordions…
in the javascript, make the first function look like this:
function runAccordion(index, AccHeight)
{
ContentHeight = AccHeight;
…the rest stays the same
Then, simply when calling the runAccordion in your HTML, call it like this: runAccordion(1,250)…this will set the size of that accordion to 250.
Quick simple fix.
January 10th, 2008 at 11:14 pm
Thank you very much. This is very nice and simple to understand
January 14th, 2008 at 8:01 pm
Answer to the Accordion One being open! Ok, I was tried the css thing someone mentioned, of course that didnt work. So sometimes thinks are simpler than one could imagine. beating head on desk for 35mins thinking about this one.. then AhA! … ok. when you click the accordion1 it runs, so instead in your body tag put onload=”runAccordion(1)” … works like a charm!!
January 14th, 2008 at 8:04 pm
also… Fix to the scroll bar arrows showing up for a blink. Change your height to fit all your content then also change the add to your accordionContent tag, accordionTitle, overflow: hidden;
January 15th, 2008 at 3:10 am
I am new to javascript..
Just a contribution to make this accordion to make multiple-open concurrently by replacing the runAccordion() method..:)
var ContentHeight = 230;
var TimeToSlide = 250.0;
var openAccordions = new Array() ;
function runAccordion(index)
{
var x;
var nID = “Accordion” + index + “Content”;
var openAccordion=nID;
var closeAccordion=”";
for(x in openAccordions)
{
if(openAccordions[x]==nID)
{//already open
openAccordion=”;
closeAccordion=nID;
openAccordions.splice(x, 1);
break;
}
}
setTimeout(”animate(”
+ new Date().getTime() + “,” + TimeToSlide + “,’”
+ closeAccordion + “‘,’” + openAccordion + “‘)”, 33);
if(openAccordion!=”")
openAccordions[openAccordions.length]=openAccordion;
}
January 15th, 2008 at 3:35 am
I use runAccordion(index, height) by DanH to set the custom height.
function runAccordion(index, AccHeight)
{
ContentHeight = AccHeight;
…the rest stays the same
Actually we can use offsetHeight to set the Actual Height of the div. For example on the html page..
Accordion 1
I Am Accordion 1.
It works! Actual height is set to the div. But the error here is that Opening has no slide-effect. The div appears immediately… though Closing works perfectly.
January 15th, 2008 at 3:37 am
Sorry ..I include html codes in previous post and what I wanted to say is.. in onclick=”" method
runAccordion(1, document.getElementById(’Accordion2Content’).offsetHeight);
January 15th, 2008 at 3:40 am
Please delete my previous post Admin..Thanks
Sorry ..I include html codes in previous post and they disappear. What I wanted to say is.. in onclick=”” method of each div..
runAccordion(1, document.getElementById(’Accordion1Content’).offsetHeight);
runAccordion(2, document.getElementById(’Accordion2Content’).offsetHeight);
..etc.
January 15th, 2008 at 7:24 am
Sorry about the bad english, my brain was frizzled. Now it is AM and i have coffee! woohoo!
1. To have the first Accordion open by default, put the javascript from your first accordion inside the “body” tag. (still keep the other one inside your first accordion tho, or it wont work when you try to close) so it will look like this:
body onload=”runAccordion(1)”
2. To get rid of those flashing scroll bars use the tag “overflow: hidden” inside your css for your AccordionTitle and AccordionContent. You will have to resize your box to make sure it all shows when complete. But that isnt too hard.
Thanks to the creator of this Post, saved me alot of time trying to reverse engineer! Awesome and clean explanation, thanks again man!
January 17th, 2008 at 12:07 pm
changed from overflow: auto, to hidden. This removed the flashing in IE.
.AccordionContent
{
height:0px;
overflow: hidden;
display:none;
}
January 23rd, 2008 at 9:23 pm
THANK YOU! Thank you so much for the updates ejgeske and Tom! Now it works exactly the way I wanted it to. Thanks again!
February 25th, 2008 at 2:13 pm
Hi! This is a great tutorial.
I have a question:
Is there a way to add a two or three levels of submenus inside?
If is, how to?
Thanks
March 14th, 2008 at 6:31 am
I made my own image & the text within the image gets chopped off, how you controll it?
March 14th, 2008 at 3:00 pm
Is there a place where the actual html portion is posted? I have set up the menu, but it operates very jerky. I must have something wrong, but I can not find it.
March 26th, 2008 at 2:58 am
Hi,
I am new to web design and coding, so need a little help in how to put this all together.
Do I create separate css and js files or just lump it all together?
Would appreciate any help.
Thanks
Paul
April 5th, 2008 at 3:09 pm
hi there,
really top notch example. keep up the great work.
just wondering if there was a way of altering the code so clicking on one header does not automatically close the header that is currently open?
April 14th, 2008 at 3:12 pm
Same question as solastyear. Can you get the menu to stay open until you click it to close? I’m brand new to javascript. I did add Swe Han’s code into the original source file and it worked. However when i added more buttons/divs it broke and now I can’t get it to work even with just 5 buttons can anyone help?
April 30th, 2008 at 11:35 pm
How do you make sub-accordians within accordians. Or to put it better a submenu within a submen?
May 29th, 2008 at 9:54 am
thanks youu.
May 29th, 2008 at 9:54 am
also… Fix to the scroll bar arrows showing up for a blink.
May 29th, 2008 at 12:53 pm
Hello. Great script! I was wondering how I can get each content area to dymanically grow when it is opened instead of having to use a set height that is set with “ContentHeight”. If anyone can help me out that would be much appreciated. Thanks!
June 2nd, 2008 at 11:01 am
Figured it out:
var ContentHeight = 1;
if(opening != null)
opening.style.height = ‘auto’;
June 3rd, 2008 at 1:25 am
thanks you.. byeeee
June 4th, 2008 at 4:33 am
Hi,
Good script,thanx it helped me a lot,but I have a question can I
implement drag stuff into this
Accordion,i.e I should be able to drag a row from somewhere outside
Accordion and put into it….
is it clear,pls help me out in this
Thanks
Poojitha
June 9th, 2008 at 10:14 am
For those of you interested I’ve modified the script to overcome the issue of static-height divs. The heights now expand depending on my content.
I added a function to the page onload event that goes through the divs and captures into an array their true heights, before they are collapsed. Then, when I expand a div I modified the routine to get the ContentHeight from the array based on the index variable. If I can work out how to post up the code I’ll do it…
June 12th, 2008 at 4:22 pm
How can I have multiple content areas open at once. I tried the code above but it didn’t seem to work. Thanks.
June 14th, 2008 at 5:49 am
thank you…
June 18th, 2008 at 2:59 am
thank you
June 19th, 2008 at 8:16 pm
I’m interested in knowing how to make the height of the divs dynamic rather than static. Awesome script!
June 20th, 2008 at 6:53 am
thank you wery much:)))))
June 21st, 2008 at 3:04 am
thank you wery much…
June 24th, 2008 at 3:11 am
thank you wery much..
June 24th, 2008 at 8:22 am
Has anyone tried to use it with a master page? I can’t make it work…
I have successfully made the accordion work on a standalone page, but when I throw the accordion on a master page and show a blank default page it falls apart; the accordion does render on the page but it doesn’t expand or collapse
June 24th, 2008 at 9:03 am
please help…
June 25th, 2008 at 8:50 am
thank you wery much…
June 25th, 2008 at 1:50 pm
Hi,
The effects seems to be great…
You will soon find it on my website, but I will try to convert it to horizontal sliding.. just thinking…
thanks for the share!!
happyhardik.
June 25th, 2008 at 3:57 pm
I also am looking to have a horizontal accordian, but I am too new at this to figure it out. Is there a spot in the CSS that would easily change to horizontal or will that take all new functions?
June 28th, 2008 at 5:42 am
thank you…
July 7th, 2008 at 10:55 am
I’m trying to have the menu not display the section header of which ever section is active… hows I do this?
July 10th, 2008 at 2:28 am
thank you…..
July 11th, 2008 at 8:15 am
thank you wery much
July 11th, 2008 at 8:28 am
thank you..
July 15th, 2008 at 3:16 am
thank you….
July 16th, 2008 at 8:50 am
thank you….
July 21st, 2008 at 8:47 am
thank you…
July 23rd, 2008 at 10:12 am
thank you…
July 25th, 2008 at 4:29 am
thank you…
July 25th, 2008 at 7:11 am
Thanks for the script works great is there a way I can make this so the menu is persisitant?
July 28th, 2008 at 2:32 pm
Great! I found it useful! However, is there a way to have background pictures in the accordions?
July 28th, 2008 at 2:33 pm
July 31st, 2008 at 7:48 am
thank you.
July 31st, 2008 at 11:28 am
Does any one know how to add a accordion within an accordion???
Cheers
August 4th, 2008 at 10:08 am
Thank you for sharing.
August 5th, 2008 at 3:27 am
Thank you for sharing
August 5th, 2008 at 8:42 am
thnak you..
August 5th, 2008 at 8:49 am
thank you..
August 6th, 2008 at 6:52 am
Thank you for sharing….
August 6th, 2008 at 2:21 pm
Thank you !
August 8th, 2008 at 2:33 am
Thank you for sharing…
August 8th, 2008 at 2:33 am
Thank you for sharing….
August 11th, 2008 at 1:16 am
Thank you for sharing…
August 14th, 2008 at 1:28 am
thank you for sharing
August 15th, 2008 at 4:27 am
hello i cant understand how to build accoidian code in my html page. please guide me
August 18th, 2008 at 10:49 am
thank you for sharing
August 19th, 2008 at 5:10 am
thank you for sharing
September 5th, 2008 at 12:18 pm
thanks..
September 15th, 2008 at 9:35 am
thanks.
September 23rd, 2008 at 12:21 am
when i used the code given above in a while loop. all accordions got opened its not collapsed on one another how to fix the problem ???
this was the code i used…