Accordion Madness

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]

Title 1

Lorem...

Title 2

Ipsum...

Title 3

Dolor...
[/html]

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.

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

[js]$(document).ready(function() { $('div.demo-show2 > div').hide(); });[/js]

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

[js]$(document).ready(function() { // ... $('div.demo-show2 > h3').click(function() { // ... }); });[/js]

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:

[js]$(document).ready(function() { $('div.demo-show2 > div').hide(); $('div.demo-show2 > h3').click(function() { $(this).next('div').slideToggle('fast') .siblings('div:visible').slideUp('fast'); }); });[/js]

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:

[js]$(document).ready(function() { $('div.demo-show2 > div').hide(); $('div.demo-show2 > h3').click(function() { [...] }); });[/js]

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:

[js]$(document).ready(function() { $('div.demo-show2 > div').hide(); $('div.demo-show2 > h3').click(function() { var $nextDiv = $(this).next(); var $visibleSiblings = $nextDiv.siblings('div:visible'); }); });[/js]

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.

[js]$(document).ready(function() { $('div.demo-show2 > div').hide(); $('div.demo-show2 > h3').click(function() { var $nextDiv = $(this).next(); var $visibleSiblings = $nextDiv.siblings('div:visible'); if ($visibleSiblings.length ) { $visibleSiblings.slideUp('fast', function() { $nextDiv.slideToggle('fast'); }); } }); });[/js]

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:

[js]$(document).ready(function() { $('div.demo-show2 > div').hide(); $('div.demo-show2 > h3').click(function() { var $nextDiv = $(this).next(); var $visibleSiblings = $nextDiv.siblings('div:visible'); if ($visibleSiblings.length ) { $visibleSiblings.slideUp('fast', function() { $nextDiv.slideToggle('fast'); }); } else { $nextDiv.slideToggle('fast'); } }); });[/js]

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.