Switch On The Code RSS Button - Click to Subscribe
Oct
22

Javascript And CSS Tutorial - Accordion Menus

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!


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>

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;
}

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;
}

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);
}

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

  1. Nick Says:

    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.

  2. Cssexpert Says:

    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

  3. Julio Says:

    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.

  4. Julio Says:

    oops, just change the class in the div that surrounds the text “I am Accordion 1.” from AccordionContent to AccordionOpen

  5. anne Says:

    Hi, how to do it without a height specified? Thanks. :)

  6. Dave Porter Says:

    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

  7. The Tallest Says:

    I hadn’t checked on the comments on this tutorial in a while, and I see there are a lot of “feature requests” :P
    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!

  8. Israel Meneses Says:

    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…

  9. Lance Says:

    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!

  10. Tom S Says:

    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

  11. Tom S Says:

    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

  12. Pau Says:

    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

  13. Pau Says:

    The display condition should be checked aswell in the first if:
    if(timeLeft

  14. Pau Says:

    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

  15. rinku Says:

    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.

  16. LM Says:

    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

  17. topher Says:

    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?

  18. DanH Says:

    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.

  19. Charitha Says:

    Thank you very much. This is very nice and simple to understand

  20. egeske Says:

    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!!

  21. ejgeske Says:

    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;

  22. Swe Han Says:

    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;
    }

  23. Swe Han Says:

    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.

  24. Swe Han Says:

    Sorry ..I include html codes in previous post and what I wanted to say is.. in onclick=”" method

    runAccordion(1, document.getElementById(’Accordion2Content’).offsetHeight);

  25. Swe Han Says:

    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.

  26. ejgeske Says:

    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!

  27. Tom Says:

    changed from overflow: auto, to hidden. This removed the flashing in IE.

    .AccordionContent
    {
    height:0px;
    overflow: hidden;
    display:none;
    }

  28. LM Says:

    THANK YOU! Thank you so much for the updates ejgeske and Tom! Now it works exactly the way I wanted it to. Thanks again!

  29. Nilmar Castro Says:

    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

  30. Sab Says:

    I made my own image & the text within the image gets chopped off, how you controll it?

  31. John Says:

    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.

  32. Paul Says:

    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

  33. solastyear Says:

    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?

  34. mofromthevilla Says:

    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?

  35. Eddie Edwards Says:

    How do you make sub-accordians within accordians. Or to put it better a submenu within a submen?

  36. bursa evden eve Says:

    thanks youu.

  37. evden eve Says:

    also… Fix to the scroll bar arrows showing up for a blink.

  38. Justin Says:

    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!

  39. Justin Says:

    Figured it out:

    var ContentHeight = 1;

    if(opening != null)
    opening.style.height = ‘auto’;

  40. hit kazan Says:

    thanks you.. byeeee

  41. poojitha Says:

    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

  42. daves Says:

    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…

  43. Justin Says:

    How can I have multiple content areas open at once. I tried the code above but it didn’t seem to work. Thanks.

  44. bursa reklam Says:

    thank you…

  45. temizlik Says:

    thank you :)

  46. Jesse Says:

    I’m interested in knowing how to make the height of the divs dynamic rather than static. Awesome script!

  47. nakliyat Says:

    thank you wery much:)))))

  48. pr yüksek siteler Says:

    thank you wery much…

  49. temizlik şirketi Says:

    thank you wery much..

  50. Ion Says:

    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

  51. Ion Says:

    please help…

  52. temizlik firmaları Says:

    thank you wery much…

  53. happyhardik Says:

    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.

  54. Star22 Says:

    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?

  55. temizlik Says:

    thank you…

  56. Adam Says:

    I’m trying to have the menu not display the section header of which ever section is active… hows I do this?

  57. kiralık vinç Says:

    thank you…..

  58. izmir evden eve Says:

    thank you wery much

  59. bursa evden eve Says:

    thank you..

  60. zemin temizligi Says:

    thank you….

  61. izmir evden eve Says:

    thank you….

  62. cit örme Says:

    thank you…

  63. genel temizlik Says:

    thank you…

  64. kiralık vinç Says:

    thank you…

  65. Ben Says:

    Thanks for the script works great is there a way I can make this so the menu is persisitant?

  66. Kapplesauce Says:

    Great! I found it useful! However, is there a way to have background pictures in the accordions?

  67. Kapplesauce Says:

    :) found it

  68. bursa reklam Says:

    thank you.

  69. Bruce Says:

    Does any one know how to add a accordion within an accordion???
    Cheers

  70. izmir evden eve Says:

    Thank you for sharing.

  71. izmir evden eve Says:

    Thank you for sharing

  72. konteyner Says:

    thnak you..

  73. konteyner Says:

    thank you..

  74. asansör Says:

    Thank you for sharing….

  75. Quy Says:

    Thank you !

  76. izmr evden eve Says:

    Thank you for sharing…

  77. izmir evden eve Says:

    Thank you for sharing….

  78. ilaçlama Says:

    Thank you for sharing…

  79. forklift Says:

    thank you for sharing

  80. nisha sharma Says:

    hello i cant understand how to build accoidian code in my html page. please guide me

  81. konteyner Says:

    thank you for sharing

  82. insaat sonrası temizlik Says:

    thank you for sharing

  83. izmir evden eve Says:

    thanks..

  84. izmir oto kiralama Says:

    thanks.

  85. bhavya gupta Says:

    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…

Tracebacks / Pingbacks


  1. hosthg » Blog Archive » Javascript And CSS Tutorial - Accordion Menus


  2. echo20 » Blog Archive » Javascript And CSS Tutorial - Accordion Menus


  3. nookli » Blog Archive » Javascript And CSS Tutorial - Accordion Menus


Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.

Powered by WP Hashcash