Accordion Madness

read 234 comments

A few weeks ago I wrote about two ways we can achieve the "accordion menu" effect, and I promised to describe a third option. Well, this is it, Option 3. But first, here is a list of my other show-hide-toggle entries, as well as Jörn Zaefferer's accordion menu plug-in:

Option 3: Zero or One

Remember from More Showing, More Hiding that we are working with a simple <h3> / <div> structure:

HTML:
  1. <div class="demo-show2">
  2.   <h3>Title 1</h3>
  3.   <div>Lorem...</div>
  4.   <h3>Title 2</h3>
  5.   <div>Ipsum...</div>
  6.   <h3>Title 3</h3>
  7.   <div>Dolor...</div>
  8. </div>

With this option #3, we start with all of the <div>s hidden. If we click on one of the headings, the following <div> will slide down. If we click on the same heading again, that <div> will slide back up. Clicking on on any heading will also hide all of the other <div>s — the ones that don't immediately follow it. Therefore, no more than one <div> can be open a a time.

Continue Reading Below

To achieve this, we start by hiding all of the <div>s inside the first (:eq(0)) <div class="demo-show2">:

JavaScript:
  1. $(document).ready(function() {
  2.   $('div.demo-show2> div').hide();  
  3. });

Then we set up the .click() method for all of the relevant <h3> elements

JavaScript:
  1. $(document).ready(function() {
  2.   // ...
  3.   $('div.demo-show2> h3').click(function() {
  4.   // ...
  5.   });
  6. });

Finally, inside the .click(), we toggle the >div< immediately following the clicked >h3< and hide all the other >div<s that are visible siblings of the toggled one. Here is the complete script:

JavaScript:
  1. $(document).ready(function() {
  2.   $('div.demo-show2> div').hide();  
  3.   $('div.demo-show2> h3').click(function() {
  4.     $(this).next('div').slideToggle('fast')
  5.     .siblings('div:visible').slideUp('fast');
  6.   });
  7. });

Now, on to the show:

Title 1

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Title 2

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Title 3

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Pretty simple, straightforward effect. Let's jazz it up a bit.

Option 3b: Zero or One, Queued Effects

Here we're going to keep the same rules about having either one or no <div>s visible at a time. But now we're going to queue the effects. In other words, we'll make the visible one slide up before the next one slides down.

The first couple lines of code are the same as those in option 3a:

JavaScript:
  1. $(document).ready(function() {
  2.   $('div.demo-show2> div').hide();  
  3.   $('div.demo-show2> h3').click(function() {
  4.     [...]
  5.   });
  6. });

But now things get a touch more complicated. We're going to set a couple variables—one for the next sibling of the clicked <h3> and one for all siblings of that next one, as long as they are visible <div>s:

JavaScript:
  1. $(document).ready(function() {
  2.   $('div.demo-show2> div').hide();  
  3.   $('div.demo-show2> h3').click(function() {
  4.     var $nextDiv = $(this).next();
  5.     var $visibleSiblings = $nextDiv.siblings('div:visible');
  6.   });
  7. });

So, now that we have the two variables, let's put them to use. We want to slide any visible sibling <div> up first and then toggle the next <div> using .slideToggle(). But we want this queued effect to occur only if there actually is a visible div. So, we'll use an if statement.

JavaScript:
  1. $(document).ready(function() {
  2.   $('div.demo-show2> div').hide();  
  3.   $('div.demo-show2> h3').click(function() {
  4.     var $nextDiv = $(this).next();
  5.     var $visibleSiblings = $nextDiv.siblings('div:visible');
  6.  
  7.     if ($visibleSiblings.length ) {
  8.       $visibleSiblings.slideUp('fast', function() {
  9.         $nextDiv.slideToggle('fast');
  10.       });
  11.     }
  12.   });
  13. });

The trick here for getting the one effect to occur after the other is to put the .slideToggle() code in the .slideUp() method's callback function.

Now, we just need to add the else condition for those times when there aren't any visible <div>s:

JavaScript:
  1. $(document).ready(function() {
  2.   $('div.demo-show2> div').hide();  
  3.   $('div.demo-show2> h3').click(function() {
  4.     var $nextDiv = $(this).next();
  5.     var $visibleSiblings = $nextDiv.siblings('div:visible');
  6.  
  7.     if ($visibleSiblings.length ) {
  8.       $visibleSiblings.slideUp('fast', function() {
  9.         $nextDiv.slideToggle('fast');
  10.       });
  11.     } else {
  12.        $nextDiv.slideToggle('fast');
  13.     }
  14.   });
  15. });

As you can see, for those cases we use a simple .slideToggle() on the next <div>.

See this code in action below. Enjoy!

Title 1

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Title 2

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Title 3

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.


comment feed

234 comments

  1. Hi Dustin,
    I'm not sure what you're referring to when you write "rollover/click text swaps." It could mean any of a number of things. Can you point me to any examples of this sort of thing on another site that I can look at? Maybe then I can write up a tutorial on how to do it.

  2. Dustin W. Gold

    I'm sorry, I just mean a rollover swap. I rollover a thumbnail image and text would change in a div box. When I click on the thumbnail the text would show in the box.

  3. Dustin W. Gold

    http://www.bartlettsfarm.com/staff.html

    This has click, but not rollover.

  4. Mark

    Great stuff! I'm desperate for a slight amend! I would like to have a different CSS style for the title you are currently looking at, ie if I'm looking at "Title 2" contents I want the Title 2 heading to have a different text colour.

    I've managed to add a class quite easily but I can't find the place to remove it! I've tried adding a toggle function but it's not happening! Can anyone help?

    This is as far as I've got:

    $(document).ready(function() {
    	$('body#faq #content p').hide(); 
    	$('body#faq #content h4').click(function() {
    		
    		$(this).addClass("on");
    		
    		var $nextDiv = $(this).next();
    		var $visibleSiblings = $nextDiv.siblings('p:visible');
    		if ($visibleSiblings.length ) {
    			$visibleSiblings.slideUp('fast', function() {
    			$nextDiv.slideToggle('fast');
    		});
    	  } else {
    		 $nextDiv.slideToggle('fast');
    	  }
    	});
    });
    

  5. Hi Mark, Right before the line with $(this).addClass("on");, try this:

    $('#faq #content h4').removeClass('on');

    There are a couple ways to optimize your code, but this is a good start and should do the trick.

  6. Mark

    Hello Karl

    Many thanks for you response.

    Nothing is happening. I think that the "addClass" immediately after the "removeClass" is turning it straight back on again. Does some kind of IF statement need to be applied?

    Regards.

  7. Hi Mark, I'll have to look at your page to see what is going on. The addClass should not be changing any of the h4 elements except the one that you click on. That's why you're using $(this) instead of $('h4') for the addClass.

  8. Mark

    Sorry, my mistake, I should have been much clearer. When I click on the title I'm currently reading, to close it down (almost as if I've refreshed the page and reset everything) the current title doesn't loose it's "on" class. It's a little pedantic but thought there might be a solution. To be honest, I was kind of getting us to the class staying on - it gives me a nice "visited" link sort of vibe!

    On an aside, if your looking for tutorial subject matter I'd love to see a jquery version of this: Ajax Sortables! I haven't seen any jquery tuts that allow you to dynamically update databases.

    Many thanks again.

  9. Hannes

    Hi,

    I am using the accordion as part of a vertical navigation with h2 as header and nested ul as the submenue that I want to hide. The toggle works fine, but somehow the hiding of the siblings doesn't work.
    Does anyone has an idea why?!?

    THANKS A LOT, Hannes

    here the jQuery:

    
    $(document).ready(function() {
           $('h2').next('ul').hide();
            $('div#sidebar> ul h2').click(function() {
              $(this).next('ul').slideToggle('fast');
              .siblings('ul:visible').slideUp('fast');
            });
          });
    

    here the html:

    
    
    
    • Portfolio
      • Flyer
      • web
    • Blog
      • projekte
      • news
  10. Hannes

    Sorry,

    here the html:

    
    <div id="sidebar">
    <ul id="nav">
    <li class="categories"><h2 class="portfolio">Portfolio</h2>
    <ul>
    	<li class="cat-item cat-item-8">Flyer</li>
    	<li class="cat-item cat-item-11">web</li>
    </ul>
    </li>
    <li class="categories"><h2 class="blog">Blog</h2><ul>
    	<li class="cat-item cat-item-12">projekte</li>
    	<li class="cat-item cat-item-13">news</li>
    </ul></li>
    
  11. great!
    good tutorial.

    best regards!

  12. sutra

    Hi, great tutorial.

    I want to use Definition List and have the behaviour sets to 'hide' in first menu (just like your example) but don't know how to modify your code.

    This is what I have from other tutorial:

    $(document).ready(function(){
    $('dt a').click(function(){
    $(this).parent().next().siblings('dd:visible').slideUp('slow');
    $(this).parent().next().slideToggle('slow');
    return false;
    });
    });

    and my markup is like so:


    Title 1

    • content for title 1
    • content for title 1

    Title 2

    • content for title2
    • content for title 2

    Please helps!

    Many thanks!

    t

  13. sutra

    Sorry, it couldn't show my markup. What I want is to use DL instead of DIV class, and I want the DTs as 'title 1', 'title 2' and 'title 3'. When the page first loaded, the DD in the title 1 is hidden.

    $(document).ready(function(){
    $('dt a').click(function(){
    $(this).parent().next().siblings('dd:visible').slideUp('slow');
    $(this).parent().next().slideToggle('slow');
    return false;
    });
    });

  14. Hi Sutra, it looks like you might need to use John Resig's nextUntil utility plugin:

    $.fn.nextUntil = function(expr) {
       var match = [];
    
       // We need to figure out which elements to push onto the array
       this.each(function(){
           // Traverse through the sibling nodes
           for( var i = this.nextSibling; i; i = i.nextSibling ) {
               // Make sure that we're only dealing with elements
               if ( i.nodeType != 1 ) continue;
    
               // If we find a match then we need to stop
               if ( jQuery.filter( expr, [i] ).r.length ) break;
    
               // Otherwise, add it on to the stack
               match.push( i );
           }
       });
    
       return this.pushStack( match, arguments );
    };
    

    Here is an example of it in use.

  15. sutra

    Hi Karl,

    Thank you so much for the reply, but the example is just a plain html page !)

    Last night I played with your code a bit further and was finally able to come out something like this:

    $('dl#cateringmenu_index> dd').hide();
    $('dl#cateringmenu_index> dt a').click(function() {
    $(this).parent().next().siblings('dd:visible').slideUp('fast');
    $(this).parent().next().slideToggle('fast');
    return false;
    });
    });

    it was Accordion menu and works great until client said no, I want the pop up window, now it's a lightbox effect lack of 'close' button' in the pop up :)

    tiny url page (not spam): http://tinyurl.com/2ckq3s

    Thanks again for the great tutorial, you explain it so well that I am finally able to wrap my head around jquery.

  16. I'm glad you found the tutorial helpful, and it's nice to see that you got something working for your client. Yeah, I probably should have pointed you to a more obvious example of the plugin. Next time. ;)

  17. I'm playing with this to make some changes to my personal portfolio site and am wondering what I need to do to make the first set of content show when a user lands on the page. For this example, I would want the content under Title 1 to be showing when the user lands on the url.

    Thanks so much for the great tutorial!

  18. ha finally step by step explanation :) thanks

  19. Jay

    Hi,

    What a great thread! A wonderful community this is! Someone else created this accordion menu and I can't seem to work out adding the functionality I need. Maybe someone could give me some help.

    I have this accordion menu that functions properly, though it reloads when a link is clicked (page referesh) so the accordion is closed instead of re-opening the menu panel with the active link. Similar to Dustin's problem above. Here it is if anyone has a few minutes to share:

    var Sisters = Sisters || {};

    Sisters.showloginform = function() {
    $('#footer #block-user').fadeIn("slow");
    }

    Sisters.buildAccordion = function() {
    var str = window.location.toString();
    var panel = 0;
    if (str.indexOf('/companions/') > -1) { panel = '1'; }
    else if (str.indexOf('/vocations/') > -1) { panel = '2'; }
    else if (str.indexOf('/support/') > -1) { panel = '3'; }
    else if (str.indexOf('/justice_peace/') > -1) { panel = '4'; }
    else if (str.indexOf('/ministries/') > -1) { panel = '5'; }
    else if (str.indexOf('/red/') > -1) { panel = '6'; }
    else if (str.indexOf('/spiritual_centers') > -1) { panel = '7'; }
    else if (str.indexOf('/meet') > -1) { panel = '8'; }

    $('ul.menu:first').hoverAccordion({
    active: 'active',
    activateitem: 'panel',
    speed: 'slow',
    keepheight: 'true'
    });

    }

    Sisters.linkActivator = function() {
    doc = document.location.href ? document.location.href : document.location;
    split = doc.split('/');
    link = split[split.length-2].toLowerCase() + '/' + split[split.length-1].toLowerCase();
    linkTwo = split[3].toLowerCase();
    if (link=='/' || linkTwo=='') {
    return;
    }
    finder = "#sidebar-left li.leaf a[@href *= '" + link + "']";
    finderTwo = "#primary a[@href *= '" + linkTwo + "']";
    $(finder).css({color: '#000000', fontWeight:'bold'});
    $(finderTwo).css({color:'#084060', fontWeight:'bold'});

    }

    Thanks in advance for your help!

  20. Hi Jay,

    Unfortunately, there is some missing information that I need to see in order to help you. You use the .hoverAccordion() method, but I'm not sure what that is supposed to do. Also, I don't see you binding a click handler to any of the links. At the very least, you should have the clicks return false on any links that you don't want to refresh the page or take you to another page. One more thing: it probably makes sense to declare your variables (doc, split, finder, etc.) using "var" to be sure you won't run into any naming collisions.

    Is there a URL where I can look at what you have so far?

  21. Jay

    Karl,

    Wow! Thanks for the quick reply.

    It's a drupal site. I didn't build it, I'm just helping out with it. Here it is: osfphila.org.ldh0242.uslec.net

    The CSS is a bit unorganized as well... .

  22. Hi Jay, No problem. You caught me at the right time. ;)

    After taking a second glance at your code and your description of what you want to have happen, I think the problem lies here:

    activateitem: 'panel',

    With this "activateitem" option, you're now saying that it should match the string "panel." But since you have a bunch of lines of code before it which try to set the value of the panel variable, I'm guessing you want to remove the quotation marks:

    activateitem: panel,

    Try that, and let me know how it works.

  23. Jay

    Hi Karl,

    Thanks for your suggestion. I just gave it a try, but no go. :(

    Any other ideas?

    Thanks,
    Jay

  24. Jay

    Wow! Karl, your website is gorgeous! Elegant, stately, and modern--all in one--brilliant.

  25. Thanks, Jay! <blushing>

    About the problem with the active section's menu items not showing, your best bet is probably to contact the developer of the hoverAccordion plugin. That activateitem option should be working with panel, as far as I can see. You should, however, remove the last line in the code now -- $(panel).show('slow');

    Here is an alternative way that you can get the active section's items to show, if it just won't work through the plugin's option:

    $(document).ready(function() {
      
      function findSection(path) {
        path = path.replace(/^\//,'');
        return path.slice(0,path.indexOf('/'));
      }
      var winPath = findSection(location.pathname);
      $('li.expanded > a').each(function() {
        if (findSection($(this).attr('href')) == winPath) {
          $(this).next().show();
        }
      });
    });
  26. Jay

    Karl,

    I can't thank you enough. You really saved the day!

  27. Odo

    Karl, great script! But I’m having visual glitches with IE7. It appears that the height of the content makes difference. Your demo works fine until I remove some “lorem…” content, in fact everything is smooth if there’s some text that fills up the div for more than 3 lines, less than that it jerks when closing. Just before final closing (last frame?) in animating I see the full open position and then it closes. I wonder why is that. Perhaps some magical css extra will solve the issue?

  28. Hi Odo,

    I can't recall offhand what causes this sort of thing, but I think it might have to do with top/bottom padding or margin. You might want to try zeroing out those properties and trying again to see if that fixes the problem.

  29. Odo

    I played around with every height affecting property that popped into my mind (height, line-height, margin, padding) but nothing seemed to fix the problem. But then I did some research on Animate effect in Jquery library itself. It has 2 methods of “easing” i.e. how the smoothness of the anim is handled – linear and swing, latter being the default one as far as I understand. And this is where things go wrong I think. So I tried to force slideToggle and slideUp to use linear instead. I achieved this with the following code:

    
       $(this).next('div').slideToggle(200, 'linear')
       .siblings('div:visible').slideUp(200, 'linear');
    

    I’m not sure why it works though :) as the second parameter, like manual and demos describe is for callback (function to be executed whenever the animation completes). Ok still, this didn’t solve problems yet – had to test with different speeds to get the right smoothness and in my case 200 seemed ok speed. So in conclusion – managed to make it work for me but I’m not exactly sure how and why it works :)

  30. Sathish

    Hi Guys,

    Do any one know how to link JQuery with a Database?
    Please provide a sample if possible.

    Thanks for your reply in advance.

    Cheers
    Sathish

  31. Hi Sathish,

    Your question is a little off topic. Anyway, you really need server-side code to communicate with the database. You can then use jQuery's ajax methods to request that code. Check out the ajax methods on the official documentation site for more information.

  32. Chad

    Hi, great tut! Just a question, let's say I have 3 links first and then 3 containers that I need to show and hide, obviously using sibling won't help since thecontainers are not sitting next to the links, what should a do in this case? Thanks!

  33. Chad

    Hi, great tut! Just a question, let's say I have 3 links first and then 3 containers that I need to show and hide, obviously using sibling won't help since the containers are not sitting next to the links, what should a do in this case? Should I use tabs instead of this approach? Thanks!

  34. Hi Chad,

    You could certainly use tabs. It's a great plugin. If you want to do this on your own, it's pretty simple. I've put together a demo page for you.

  35. Ryan

    First off, thanks for the very informative website. I implemented some code base on your suggestions and I am plagued with a minor bug:

    http://ryanlsmith.com/tmp/jquerytest/index4.html

    If you check the aforementioned URL, the accordian works but after being clicked the layers don't hold their positoin and overlap some. I am assuming this is a problem with the div style attributes, can you offer some advice? Thanks in advance-
    -Ryan

  36. Hi Ryan,

    The problem is that all the divs inside each container div are floated, so they are outside the flow of the document. Adding clear: all; to .menu {} should do the trick. Let me know if that doesn't solve the issue for you.

  37. Oops. Rather than .menu { }, that should, of course, be .menubar { }

  38. Ryan

    Hi Karl-
    Thanks for the response. I tried your suggestion and had no luck. Any other ideas? When I set the float:left attribute it fixes the current problem but the collapse no longer works right. Any ideas? Thanks in advance-
    -Ryan

  39. Hi Ryan,

    Hmm. I didn't suggest using float:left. I just looked at your page again, but I didn't see clear:all; applied to the "menubar" class in the styles. Please do that, and if it still isn't working, I'll examine it more carefully.

  40. Bob

    Hi, I tested the code and works fine in Firefox. It does work in IE but there were some annoying "Flickerings".

  41. Nik

    Thanks! Works great

  42. milkshake

    Thanks, I was trying to figure that out for ages ;)

  43. when i enter links in the div tag that is the content of the accordian everything seems to work fine in firefox but in internet explorer the links just flash once and dissappear after that

    another problem with firefox is that my first title of accordian like in this pages its title 1 seems to dissappear in internet explorer

  44. Binusha Perera

    hi

    I am quite new to the jQuery and I am using it for my main menu navigation, the question i have is when i go to a new page from a link on the menu how do i keep the state (selected menu displayed in the accordion). Is there a simple way to do this ?

    Thanks
    Binu

  45. Ok: I've got something

    <div class="demo-show2">
      <h3>Title 1</h3>
      <div>Lorem...</div>
      <div>Lorem...</div>
      <h3>Title 2</h3>
      <div>Ipsum...</div>
      <div>Ipsum...</div>
      <h3>Title 3</h3>
      <div>Dolor...</div>
      <div>Dolor...</div>
    </div>

    I want i to toggle but I can't do it with the second div. Anyone got an idea how to toggle all divs and not only one?

  46. Binesh, please take a look at the cookie plugin. That should help you achieve what you're attempting. I have a demo page using it that might be helpful

    Rockstyle, you probably need to use John Resig's nextUntil utility plugin:

    $.fn.nextUntil = function(expr) {
       var match = [];
    
       // We need to figure out which elements to push onto the array
       this.each(function(){
           // Traverse through the sibling nodes
           for( var i = this.nextSibling; i; i = i.nextSibling ) {
               // Make sure that we're only dealing with elements
               if ( i.nodeType != 1 ) continue;
    
               // If we find a match then we need to stop
               if ( jQuery.filter( expr, [i] ).r.length ) break;
    
               // Otherwise, add it on to the stack
               match.push( i );
           }
       });
    
       return this.pushStack( match, arguments );
    };
    

    Here is an example of it in use.

  47. Any idea, how to do it without additional plugins? Maybe I sould put these two divs inside one and toggling only that one.

  48. Yeah, I think wrapping the two divs inside a single div would make the most sense.

  49. Bladescope

    Hey, first off, thanks of for the script it's greatly appreciated.

    Second off, is there any way to replace the h3 tags with divs instead?
    E.g.

    Title 1
    Content
    Title 2
    Content
    Title 3
    Content

    Any help would be helpful, thanks in advance,
    Bladescope

  50. Bladescope

    Apologies for the double post, but i'll rephrase. Here's an example of the code I would like to use with the script:

    Style:

    
        <style type="text/css">
    	div.box {
    	border: 1px solid black;
    	width: 300px;
    	float: left;
    	}
    
    	div.desc {
    	border-bottom: 1px solid black;
    	border-left: 1px solid black;
    	border-right: 1px solid black;
    	width: 300px;
    	clear: left;
    	}
    
    	div.class {
    	float:left;
    	width:200px;
    	}
    
    	div.status {
    	float:left;
    	width: 100px;
    	}
        </style>
    

    Code:

    
    	<div class="demo-show">
    	<div class="box">
    		<div class="class">{Class}</div> <div class="status">{Status}</div>
    	</div>
    	<div class="desc">{Description}</div>
    	</div>
    

    Again, it's a great script and thanks for showing it to us :D

    Any help would, again, be appreciated.
    Bladescope

  51. Hi there,
    Sure it's possible. It's unclear to me which div(s) you want to bind the click event to and which one(s) you want to hide and show. Do you want the "description" div to appear when you click the "class" div? When you click the "status" div? Both? Neither? I'm confused.

    However you have it set up, I think the trick for you will be to use a combination of child/parent selectors and the this keyword.

  52. Yo!

    Very nice script..however i've encountered a problem though. It basically 'jumps'. So the content appears, then jumps up about 10 pixels. When you click to close, it jumps down the same amount, the new content appears and same thing happens.

    Turns out it happens when you include p tags inside the divs that get shown/hidden.

    To solve this problem, you have to make sure those p tags are given margin and padding of 0px in your css. Number of ways to do this, but best to give each div your showing/hiding the same class (such as 'showhidecont') and put this in your css

     
    .showhidecont p
    {padding:0px;
    margin:0px;}
    

    Problem solved!

    :)

  53. Philip

    Karl,
    some great tutorials on jquery here, thanks a lot. I'm very interested in your (Tab Example). I was wondering how I would go about hiding all the panels (instead of having one automatically showing) and having them slide up and down on-tab-click like this accordion example? i.e. zero or one.
    -Philip

  54. Utecorrenobre

    Tahnks for posting

  55. Hi Philip,

    Check out this demo.

  56. Philip

    Thanks Karl! That's fantastic. My skills are mostly (X)HTML and CSS but having seen your site, the demos, and your helpfulness I think I'll add your jQuery books to my bookshelf!
    -Philip

  57. Anyone ever use this application with an unordered list and sub menus? I have a client that wants to have a vertical navigation able to reveal sub navigation for each section on rollover. I realize i could set it up as individual s but would like to maintain my

      i have already created. Any help is appreciated.

      Thanks.
      Josh

  58. Brad

    I'm migrating a site onto a new CMS and they used an old version of accordion that I just couldn't get working with the newest version of accordion and jquery.

    Your code took about 10 minutes to get working once I figured out I needed to use # instead of . since I use an ID on my main div!

    Very awesome tutorial.

  59. Marko

    Hi,
    every time I use slidetoogle, the content wich is hidden just before slideing shows up in a milisecond completly, hides back, then he slides down, and when I click to slideup, he slide just fine, and when he rich end, he do this reset - streching thig again in milisecond, and then it hides again.

    I dont get it, because I am using examples code above, but when I trying it here on your page everything is just fine, so I suppouse this hasnt nothing to do with IE6 wich I am useing.

    Thanks.

  60. Hi Marko,

    If it works here but not on your page, I guess the first thing to do would be to see what the differences are between the two pages. You might want to start by looking at the CSS. If you'd like some help, post a link to the page in question.

  61. Marko

    Hi Karl,
    I figure out that toggle function doesnt work good for me, but when I use hide and show alone it works great, so I am using

    $(document).ready(function() {
    $('div.demo-show2> div').hide();
    $('div.demo-show2> h3').click(function() {
    $(this).next('div').show(500)
    .siblings('div:visible').hide(300);
    });
    });

    and now I need only to close existing (with hide, not with toggle) without oppening new , so can I tell something like "If click on existing one wich is oppened, hide it"?

  62. Patrick

    Thank you very much for this awesome tutorial !!

    I am really happy with this,superb !

  63. Hey guys, I'm new to this... I have put together the Accordian panel, but am having problems with one thing. I really want to have an additional heading within each panel. For some reason the as soon as I add a subhead and add a or or

      etc. the panel will not hide or work for that manor. Is there any way to style an additional heading (other than the standard H3). Thanks for any light you can shed on this.
  64. sorry about last post.. It left out the tags... h5, div, ul, li etc.

  65. Tyler B.

    Hello Karl,

    This code/post has been incredibly helpful. There's a good variation on this here (scroll to example 4) that expands on this code to include a class toggler and more.

    I do have a question. Would it be possible to do an "upside-down" version of this accordion? For instance, if I clicked on "Title 2", Title 1 & 2 would shift up, Title 2's div would reveal and also shift up, and Title 3 would remain stationery during this whole fiasco. I've tried experimenting and Googling, but no such luck (plus I'm not even sure what to use as search terms. Upside-down accordion script? Bottom align accordion script?). Part of my brain refuses doesn't believe the internet will even allow this to work.

    If you know of any solutions, scripts, or even any initial hints of an idea, that would be most helpful.

  66. samy

    hi karl,

    I have a non accordian question.
    i’m trying to use the following code and i want to hide a div “.nextblock” when i click any where on the page, except on that div. But this is not working. It hides the block even if i click on the div “.nextblock”.

    $(”body,div”).not(”.nextBlock”).click(function () {

    $(”.nextBlock”).hide();

    });

    I tried using filter() instead of not. That does not work either.

    I would appreciate if you could sujjest some thing.

  67. I have failed to implement the above for the following... on clicking the word "change" it should toggle the 'secondchild'... I can do this one 'firstdiv' but then it goes on the next 'seconddiv'. How can I implement the above method with different parents...


    #secondchild{ display: none; }

    NameChange
    Full NameSantosh S Kumar

    ...

    NameChange
    Full NameSantosh S Kumar

    ...

  68. Sorry the was not enclosed in pre...
    I have failed to implement the above for the following... on clicking the word "change" it should toggle the 'secondchild'... I can do this one 'firstdiv' but then it goes on the next 'seconddiv'. How can I implement the above method with different parents...

    #secondchild{ display: none; } 
    
    
         
               NameChange
               Full NameSantosh S Kumar
         
        
             ...
        
    
    
    
         
               NameChange
               Full NameSantosh S Kumar
         
        
             ...
        
    
    
    
    
  69. I am extremely sorry for the above two comments.. they were not properly wraped inside the tags... I kind of figured out by changing the HTML layout. Thank you so much for the post.

  70. Jomy

    Any way to implement Accordion--when clicks on title it need to open a new page along with expanding

  71. Deon

    Hi karl, i have followed all the example from above but my code just doesnt work... and one question, wher do i get the "more-show-hide.js" ?

  72. Giorgio

    Hello,
    i have a 3rd levels menu using jquery. Now i wish to know how to select a menu voice when landing to a page. Please can you make me an example on how i can select "coordinamento" (2level voice) and "milano" (3rd level voice)?
    Thank you in advance

    
    <ul id="theMenu">
    			<li>
    				<h3 class="head"><a href="javascript:;">Charles Darwin</a></h3>
    				<ul>
    					<li>
    	                    <ul id="xtraMenu">
                            	<li>
                                	<h4 class="noclick"><a href="biografia.php">Biografia</a></h4>
                                    <!--<h4 class="head"><a href="bibliografia.php">Bibliografia</a></h4>-->
                                    <h4 class="head"><a href="javascript:;">Darwin Year</a></h4>
                                        <ul>
                                        <li><a href="lectio.php">Lectio Magistralis</a></li>
                                        <li><a href="spettacoli.php">Spettacoli</a></li>
                                        <li><a href="caffe.php">Caffè Scientifici</a></li>
                                        </ul>
                                </li>
                            </ul>
                        </li>
    				</ul>
    			</li>
    			<li>
    				<h3 class="head"><a href="javascript:;">Mostra</a></h3>
    				<ul>
    					<li>
                        	<ul id="xtraMenu2">
                            	<li>
                                	<h4 class="noclick"><a href="tema_mostra.php">Il tema</a></h4>
                                    <h4 class="noclick"><a href="percorso.php">Il percorso</a></h4>
                                    <h4 class="noclick"><a href="curatori.php">I curatori</a></h4>
                                    <h4 class="head"><a href="javascript:;">Sedi mostra Italia</a></h4>
                                    	<ul>
                                        <li><a href="roma.php">Roma</a></li>
                                        <li><a href="milano.php">Milano</a></li>
                                		</ul>
                                    <!--<h4 class="head"><a href="biglietti.php">Biglietti e prenotazioni</a></h4>-->
                               </li>
                          </ul>
                     </li>
                </ul>
    	   </li>
    			<li>
    				<h3 class="head"><a href="javascript:;">Didattica</a></h3>
    				<ul>
    					<li>
    	                    <ul>
                            	<li>
                                	<!--<h4 class="head"><a href="programmaDidattico.php">Programma didattico</a></h4>
                                    <h4 class="head"><a href="giochi.php">Giochi</a></h4>-->
                                    <h4 class="noclick"><a href="cartoon.php">Cartoon</a></h4>
                                    <h4 class="noclick"><a href="gallery.php">Immagini</a></h4>
                                </li>
                            </ul>
                        </li>
    				</ul>
    			</li>
    			<li>
    				<h3 class="head"><a href="javascript:;">Organizzazione</a></h3>
    				<ul>
    					<li>
    	                    <ul>
                            	<li>
                                    <h4 class="noclick"><a href="direzione.php">Direzione</a></h4>
                                	<h4 class="noclick"><a href="coordinamento.php">Coordinamento</a></h4>
                                    <!--<h4 class="head"><a href="sponsor.php">Sponsor</a></h4>-->
                                </li>
                            </ul>
                        </li>
    				</ul>
    			</li>
    			<li>
    				<h3 class="head"><a href="javascript:;">Info & News</a></h3>
    				<ul>
    					<li>
    	                    <ul>
                            	<li>
                                	<h4 class="noclick"><a href="news.php">News</a></h4>
                                    <h4 class="noclick"><a href="link.php">Link</a></h4>
                                    <h4 class="noclick"><a href="contatti.php">Contatti</a></h4>
                                    <!--<h4 class="head"><a href="salaStampa.php">Sala stampa</a></h4>-->
                                </li>
                            </ul>
                        </li>
    				</ul>
    			</li>
    </ul>
    
  73. Karl

    thanks a lot, very helpful

  74. Rodrigo

    thanks!!!!

  75. thanks alot, helpfull as all other published on this site

  76. sourasis

    testing for live preview of comments. its really great!

  77. Just a note for anyone who is having trouble with links flashing and then disappearing in Internet Explorer. It is most certainly a css issue and most likely a position bug (what else is new micorsoft?)... I had a default setting for my divs in css...

    div { position:relative }

    Once I deleted this, everything worked fine.

  78. David

    Hello all.

    I am new to both jQuery and the Accordian control and am trying to adapt the tutorials to fit my requirements. My twist on the common behaviour is that I'd like each div be a different color when it is selected. All unselected divs would remain a single color. Anyone know if this is possible and if so, how?

    Thanks!

    • Oskar Rough

      David,

      It's quite easy to add and remove css classes with jQuery. This little code removes all classes with the name of "on" and adds a class of "on" to the clicked element.

      $('.box div').removeClass('on');
      $(this).next('div').addClass('on');
      

      Remember to put it inside your click function. I hope it works, my first time with jQuery ;)

      On another note. The slide animation looks rather chunky both in FF3 and Safari (Mac) here. Any ideas why this is?

  79. DGV

    How to use this accordion menu for business applications?.
    I would like to populate the menu dynamically from table, based on user privileges.

  80. Hi Oskar, I used your example which is working fine. I wonder if you can tell me how to remove the 'on' class when I click the h3 handle again and close the div.

  81. nb

    Anyone know how to fix the jumping animation? It starts smooth, but ends poorly, at least in Firefox and Safari.

    Anyone?

  82. Sandy

    Hi this should be simple...I have a test accordion...just five bars....I want to set the visible
    bar via a button (just for a test) I use the code:

    
     <input id="GreenButt" type="button" value="Green" onclick="$('#accordion').accordion('option', 'active', 2);"/>
    

    I can't seem to touch the accordion element which is declared as:
    <div align="left" id="accordion">

    I have another button that is using alerts to tell me the value of the active variable and
    that shows that the variable is being set correctly, but the damn accordian isn't moving.
    help oh kind souls ;-)
    thanks in advance....Sandy

  83. Jos De Berdt

    There are 2 kinds of "jumping" accordions.

    - caused by the padding and/or margins
    - caused by the variabel width or height of the item in the sliding container. (width = X %)

  84. Jason

    Hi Karl

    I've scoured the net for hours but can't come up with the specific problem I'm having. I've integrated your accordion into the website I've built. I'm updating the website in such a way that the accordion will load into a div via AJAX. As I understand it I need to use Brandon Aaron's Livequery to get this working. Problem is I can't figure out how I would implement it into your code above.

    Bearing in mind I'm more of a copy/paste code designer-type, this is what I tried:

    
    $(document).ready(function() {
      $('div.demo-show2> div').livequery(function(){ 
            $(this) 
                .hide(function() {
    			 
      $('div.demo-show2> h3').livequery('click', function() {
        $(this).next('div').slideToggle('fast')
        .siblings('div:visible').slideUp('fast');
    	return false;
      });
    });
    

    Help would be massively appreciated because for a while now I've been building my websites with AJAX but somehow sidestepping a lot of the problems that can occur without using Livequery by using other methods that didn't need rebinding. Your accordion, however, definitely seems to need it though.

    Thank you.
    Jason Walter

  85. macLover

    Hi, thanks for the great article Karl. This is wonderful. I am very new to jQuery and it helps me a lot. I have tried to add the 'remove class' function but it is not working...I can't figure it out how to do this..Please give me an advice. Thank you.

    
    $(document).ready(function() {
      $('div.demo-show:eq(0) > div').hide();  
      $('div.demo-show:eq(0) > h3').click(function() {
        $(this).next().slideToggle('fast');
    	$(this).addClass('on');
        return false;
    
      });
    });
    
    $(document).ready(function() {
      $('div.demo-show:eq(1) > div:gt(0)').hide();  
      $('div.demo-show:eq(1) > h3').click(function() {
        $(this).next('div:hidden').slideDown('fast')
        .siblings('div:visible').slideUp('fast');
    	$(this).removeClass('on'); //this is not working...
        return false;
    
      });
    });
    
  86. Jason

    Any help at all please?

    • Hi Jason,
      It looks like you have some errors in your script.
      I'd love to help you, but my time is really limited right now. Would you mind directing your question to the jQuery Google Group? I think you'll have a much better chance of getting a satisfactory answer and will be able to follow up with additional questions more easily. Please describe as clearly as you can the outcome you're trying to achieve and show the code that you have written so far. Thanks!

  87. Seb

    Hi there,

    It's a very nice source - however there seem to be a very quick flick a the end of the sliding down - did you notice that?

    Also - I would be interested in seeing this script with the change of the class of the trigger - to indicate its active state when clicked and container is shown.

    Many thanks

  88. Griffo

    Brilliant tuts, excellent site. I was wondering (as a newbie to all this) is there a way to play the menu and then once it's fully collapsed jump to a URL. Basically I have an unordered list of links some with submenus some without, if I have the menu extended and then click on another I'd like the menu to collapse before jumping to the new page? Sorry if that is confusing.

  89. Chris

    As someone else asked... where do I get more-show-hide.js? I dont see the link anywhere on here for it and cant find it on your server.

  90. I want to be able to add a class to the h3 when its clicked on and opens, but when you open another h3 I want that h3 to have a class added to it and the previous one to remove the class, whats the best way to do this? On another note, got 3 of your jQuery books and loving them!

    • Hi Alex,
      The this keyword comes in handy for this type of thing:

      $('h3').click(function() {
        $(this).addClass('active').siblings('h3').removeClass('active')
        // ... accordion stuff ...
      });
      

      That will always add the class to the clicked h3. You can use .toggleClass('active') rather than .addClass('active') if you want to toggle the class.

      • Hi Karl

        I'm totally new to js and jquery. Your code is awesome! And the .toggleClass('active') works really beautifully. Thank you.

  91. Josh H

    Is there a way to use this option but have 'Title 1' be open by default?

  92. George

    Hi all!
    New to this jQuery stuff, but loving the learning.. ; )

    Along the journey, though, I've stumbled upon something I can't quite get past.

    My site is on an intranet, so you wouldn't be able to access it unfortunately. The basic issue is that I've structured my page to dynamically load html files into divs, when a menu link is clicked.

    I'd love to use the accordion widget in one of these html files [actually, I'd love to use the ToggleBoxes one, since I'd like the users to be able to have more than one section open at a time]. When I open the html file containing the accordion code, it appears as expected. I can click the headers & the div expands. Beautiful!

    However, when I try to have that page opened up into a div called changeForm. There's nothing super-special about this div [no css, etc]. But, what was the beautiful expanding accordion is now just a couple panels with headers as links, divs completely visible & no fancy expanding / collapsing functionality. This makes me sad.

    Any ideas why it might work when viewing as a normal html page, but not when it's trying to be loaded dynamically into changeForm?

    I'm be willing to post code, but it's kind of all over the place in different javascript, css, and html files.

    Thanks in advance for any clues..

    - George

  93. hi
    i don't know if there is an answer to this yet, but i would like to make it in the opposite direction, i mean, when you click on an option this has to go up not to go down, i haven't seen this yet in all the web

    thanks, for your help..
    best

  94. Nevin

    Hello,

    I am new to JQuery UI.

    While using the Accordion widget, I need to display some links in-
    between the tags. However, when I try the normal way of doing
    it: Test Page, in fact, the words "Test Page"
    disappear completely from the text.

    I would be grateful if somebody can help me out!

    Thanks

    -- Nevin

  95. Oakabilly

    First of all THANKS!
    there is a way to do something like this?

    Title 1
    Title 2
    Title 3
    Dolor...
    Lorem...
    Ipsum...

    If i click on first header i will see first div, clicking on second the second div... etc??

    • Sure. If your titles all have class="title" and the panels all have class="panel," you can do this:

      $('.title').each(function(index) {
        $(this).click(function() {
          $('.panel:eq(' + index + ')').slideToggle();
        });
      });
      Of course, you can give them whatever class you want. It's just a matter of tying the index of the clicked element to the index of the thing you want to act upon.
      • Oakabilly

        Thanks very much for reply.
        I express myself bad (and my english doesnt help me!), and what i'd like to do is something different: when i click on one of the title all panels slide up and the panel i wanna show slide down.

        Using ur code, i did this. It works to me. I hope is a good coding, i'm on my "second jQuery day"! Thanks 4 all.

        
        $(document).ready(function() {
          $('.title').each(function(index) {
            $(this).click(function() {
              $('.panel').slideUp('fast');					   
              $('.panel:eq(' + index + ')').slideDown('slow');
            });
          });
        });
        
        • Nice job. Glad you got it to work the way you want it. I would just change this part:

          
                $('.panel').slideUp('fast');
                $('.panel:eq(' + index + ')').slideDown('slow');
          

          … to this:

          
            $('.panel:eq(' + index + ')').slideDown('slow')
                .siblings('.panel').slideUp('fast');
          
        • Oakabilly

          Finally I did this:
          $('.panel:eq(' + index + ')').slideToggle('slow')
          .siblings('.panel').slideUp('fast');

          Thanks very much for help and time you gaved to me!
          Ciao!

  96. anyone get this working with fixed height and no bottom jump bug seen on IE6,IE7 and Safari?

  97. Javier Rios

    Thank you for this tutorial it has been a great help. I am facing a problem that I am unable to solve though. My structure is similar to your with one difference, the H3 and div following are wrapped in a Div. This is done so that I can hide or show certain sections depending on your rights.

    There are also times when the H3 is followed by a UL instead of a div. In the js I put the class name to show or hide.

    I am able to get the h3 to toggle between the div or ul, I am not able to get it to show or hide other open divs or uls. I will have multiple sections open instead of one closing as another is being open.

  98. Austin Siewert

    Karl, any way to activate the accordion from outside? For instance, I would like to open/close the div's via the H3's or from an outside <a&gt's. I have the accordions wrapped in #accordion div and have <a>'s in a sidebar with the same classes on the anchors as the #accordion > h3's. Does that make sense?

    • Hi Austin,

      Sorry I don't have time for a detailed reply, but the answer is yes. Something like this would work (if I'm understanding your html structure correctly):

      
      $('.sidebar a').click(function() {
        var thisClass = this.className;
        $('h3.' + thisClass).trigger('click');
        return false;
      );
      
      • Austin Siewert

        Thanks Karl,

        So cool and so simple!!! I always make it harder on myself than it needs to be. I guess that goes with the territory as I'm just getting into jQuery and don't know the full API.

        I'm actually going to order your book tonight, been thinking about it for awhile and now is the time!

20 Pings

Sorry, but comments for this entry are now closed.