A Insanley Simple jQuery Accordion

We have a couple of projects currently running in parallel and as always resources are a bit in short supply. This has given me the opportunity to put on my developer hat a bit and help out a bit. This time with building a simple jQuery accordion. I didn't want to use the accordion widget so I quickly put together a quick little example for the developer to integrate into the project.

The HTML

I went with a very simple structure for the accordion. A single div that defined the block and then an h2 for the header and a paragraph tag for the accordionPanel (you could change it to a div without affecting the behavior).

<div class="accordion">
<h2>Header</h2>
<p class="accordionPanel">
some body content
</p>
<h2>Header</h2>
<p class="accordionPanel">
some body content
</p>
<h2>Header</h2>
<p class="accordionPanel">
some body content
</p>
<h2>Header</h2>
<p class="accordionPanel">
some body content
</p>
</div>

The Css

I only went with two classes, naturally to be truly useful you need to make it look pretty, but that can always be done later. First get it to work and then later make it look nice.

<style>
.accordionPanel{
display:none;
}
.accordion h2 {
cursor:pointer
}
</style>

The jQuery Code

The jQuery code could probably be optimized but I still think it's pretty simple code and it works!

I attach an click event to every h2 inside the accordion div. This should probably be changed so that it looks for a class on the h2 in case you have h2's inside the accordion body.

I then grab the sibling that has the class of accordionPanel. I then set up a variable to hold all the accordionPanels since I only want one panel to be open at a time.

I loop through my array of panels and slide them all closed, then open only the panel that was just clicked.


<script language="javascript">
$(document).ready(function(){
$('.accordion h2').click(function(ev){
var el = $(ev.target).next(".accordionPanel");
var els= $('.accordionPanel'); /*get a reference to all products*/
/*close all open accordion panels*/
for (i=0;i<els.length;i++){
if ($(els[i]).css("display")=="block") {
$(els[i]).slideToggle("slow");
}
}
/*slide the selected product open*/
el.slideToggle("slow");
});
});
</script>
So there you have it an Insanley Simple jQuery Accordion. I love jQuery for how straightforward it is.

The Promised Live Example


Header

some body content

Header

some body content

Header

some body content

Header

some body content


10 Comments to "A Insanley Simple jQuery Accordion"- Add Yours
andy matthews's Gravatar No demo? Obviously I could copy and paste the code myself, but I'm always interested in seeing demos on other people's sites. Part of the process IMO. You're right though, and jQuery does indeed rock.
# Posted By andy matthews | 3/19/09 12:09 AM
Gary's Gravatar @andy,

Good point, I will update with a live example
# Posted By Gary | 3/19/09 4:43 AM
Kyle Farris's Gravatar You are apparently missing out on the true simplicity of jQuery. Try this on for size:

$(function() { $('.accordion h2').click(function() { $(this).parent().find('.accordionPanel:visible').slideUp('slow').end().end().next('.accordionPanel:hidden').slideDown('slow');}); });

That's, for all intents and purposes, basically a one-line version of your script. Could be faster, probably, but, the purpose of this was to see if I could turn your code into one line of jQuery. Chaining is your best friend. Good luck with all your jQuery learning...
# Posted By Kyle Farris | 3/20/09 1:11 AM
Gary's Gravatar Err....*blink*...*blink*

I wouldn't exactly call that simple. But I guess my code shows my experience level with jQuery, as does yours :)

I'll be honest I got lost at the .end().end().next part
# Posted By Gary | 3/20/09 3:14 AM
Kyle Farris's Gravatar It's okay, this is quite advanced jQuery. Here's the breakdown of how it works:
When an H2 that's located inside an element with class 'accordion' is clicked it is passed as a jquery object to the function that is the first parameter of the click method. You already understood this part, so I won't elaborate. Now, inside this function, the clicked element can henceforth be referred to as: $(this) (which is moreorless equivalent to your $(ev.target)). On that note, when you call the parent() method on $(this) you are getting the direct ancestor of the element (in this case, that would be the '.accordion' element). Now the currently active object is the parent of the clicked element. So, any methods you run hereafter will be applied to the parent (this is called a 'destructive' method because the initially selected element (this) is no longer the active object in the jQuery chain). If you understand that part, you are ready to move on...
Now, the find() method is called on the currently active object (the parent of the H2, also known as '.accordion'). What the find method does is looks only within the scope of the object that the find method is applied to. So, in this case, it will find all elements that match the CSS selector that is passed in the find method ('.accordionPanel:visible'). What this method/parameter pair is doing is: finding all elements within the '.accordion' element that have the class 'accordionPanel' and are visible. The find method is another 'descructive' method so if you remember, that means that the currently active object is now an object containing only the elements that have the class 'accordionPanel' and are visible. All those mathching elements will now "slide up slowly" due to the slideUp method that is applied to the object.
Okay, here's the tricky part. What's happening with the 'end()' methods is this: the end method 'rolls back' a descructive method. So, since our currently selected object contains all the elements within the '.accordion' element that have the class 'accordionPanel' and are visible, the end() method would roll us back to just the parent of $(this) (i.e, '.accordion'). If you run the method again on that object, you'll be rolled back again so that the currently selected object is now just $(this).
Okay, now that we are rolled back to the element that was originally clicked, let's find the '.accordionPanel' that is directly next to it (and no others). And, for good measure, let's filter out any chance that it's already visible. SO... if it IS hidden, then let's slowly slide it down.
# Posted By Kyle Farris | 3/20/09 4:14 AM
Mark's Gravatar Hi,
i am using another jquery tool on the same page as this and it has the effect of making the accordion inoperable. Is there a command to "reset" the accordion, so that all of its event hanlders and positons etc are all defaulted?
Thanks,
Mark
# Posted By Mark | 6/17/09 4:28 AM
tim's Gravatar @gary Thanks for the great post.

@kyle Thanks for sharing as I never fully understood what how to go from .parent().siblings('h5') then back to this all in one chain...end() is awesome. Happy chaining.
# Posted By tim | 8/12/09 7:28 AM
Jonrp's Gravatar I'm only a humble code hacker, but I can't get this script to do anything at all in IE v6-8....
# Posted By Jonrp | 2/24/10 11:22 AM
Gary Gilbert's Gravatar @ Jonrp,

and the live example above doesnt work for you in IE either?

view the source and you will see the working code, it works in ie6-8 without problem
# Posted By Gary Gilbert | 2/24/10 1:47 PM
Michael's Gravatar This is for Andy Matthews - there is a demo - look for
Header
Header
Header

I must say though that the jQuery UI accordion is very simple too and very configurable.
# Posted By Michael | 4/28/10 1:20 PM

Powered By Railo

Subscribe

Subscribe via RSS
Follow garyrgilbert on Twitter Follow me on Twitter
Or, Receive daily updates via email.

Tags

adobe air ajax apple cf community cfml coldfusion examples ext flash flex google javascript max2007 max2008 misc open source programming railo software technology ui

Recent Entries

Converting structkeys to lowercase

Blogroll

An Architect's View
CFSilence
Rey Bango
TalkingTree

Wish List

My Amazon.com Wish List