Stupid Simple jQuery Accordion Menu
Last week I had to create an accordion style menu for a project. Accordion menus are a very, very handy tool to show and hide information as needed. I have used them on sites like http://www.spokanesymphony.org and http://2008-2009.spokanesymphony.org. While the accordion system I used on these sites worked well, I decided to write my own using jQuery with the goal of making it as simple as possible.
I have found many of the existing accordion menu systems to be bloated and difficult to understand. I knew there had to be an easier way to create an accordion menu. Instead of using a list like most alternate systems, this system uses a grouping of DIV elements with specific names.
DEMO | DOWNLOAD
Note: Here is an example of how to pin open the first item and an example of how to select any item to pin open on load.
How to implement this jQuery accordion style menu:
Step 1 – Include jQuery:
For a jQuery beginner the first thing you need to do is to include the jQuery library. Google hosts the library so you can link to it there. This can be done by putting the following code in the head of your document:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"> </script>
Step 2: – Create the JavaScript
Next you need to create a blank JavaScript file. For the example, this file is called javascript.js. This file will contain the jQuery code required for the menu. Once you save the file include it in the head of your document with the proper path just as we did the jQuery library in Step 1. An example of the JavaScript code to include in this document is shown below:
$(document).ready(function() { //ACCORDION BUTTON ACTION $('div.accordionButton').click(function() { $('div.accordionContent').slideUp('normal'); $(this).next().slideDown('normal'); }); //HIDE THE DIVS ON PAGE LOAD $("div.accordionContent").hide(); });
Step 3 – Create the CSS:
Now we need to create a CSS document with our two selectors accordionButton and accordionContent and then include that in the head of the document. Examples of these selectors are included below. The color, contents, and visual formatting can all be manipulated. It is important these elements retain their float: left or display: inline-block property so that they will display inline.
#wrapper { width: 800px; margin-left: auto; margin-right: auto; } .accordionButton { width: 800px; float: left; background: #003366; border-bottom: 1px solid #FFFFFF; cursor: pointer; } .accordionContent { width: 800px; float: left; background: #95B1CE; display: none; }
Step 4 – Create the HTML:
Now we need to create the HTML we’re going to manipulate. For this example we will keep the page very, very simple. In a more complicated HTML document you need to make sure the two classes used for the accordion DIV items are not used elsewhere. jQuery will be looking for the class of the element so if it is present elsewhere in the HTML document it will cause some unexpected problems. The full HTML document also displaying the includes is shown below:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>jQuery Accordion Style DIV Menu</title> <link href="style/format.css" rel="stylesheet" type="text/css" /> <link href="style/text.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"> </script> <script type="text/javascript" src="includes/javascript.js"> </script> </head> <body> <div id="wrapper"> <div class="accordionButton">Button 1 Content</div> <div class="accordionContent">Content 1<br /><br /><br /><br /><br /><br /><br /><br />Long Example</div> <div class="accordionButton">Button 2 Content</div> <div class="accordionContent">Content 2<br /><br /><br /><br /><br />Medium Example</div> <div class="accordionButton">Button 3 Content</div> <div class="accordionContent">Content 1<br />Short Example</div> <div class="accordionButton">Button 4 Content</div> <div class="accordionContent">Content 4<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Extra Long Example</div> </div> </body> </html>
Notice that we have alternating rows with the styles accrodionButton and accordionContent. Clicking accordionButton will trigger the drop of the next instance of accordionContent. It is very important these elements alternate properly with nothing inbetween for the system to function properly. Each element can contain HTML, nested divs, or other styling elements.
Step 5 – Check out the Result!:
Now we have all of our code we need. View the system in the browser and it should work great. Clicking on each button will cause the content below it to drop. The content will retract if another button is clicked. (Note: If you needed to keep the content elements open after a click on a seperate button instead of having them retract you can do this easily by removing this line from the javascript.js include:
$('div.accordionContent').slideUp('normal');
View a complete example or download a complete example:
Click here to view the demo of the accordion style jQuery menu
Click here to download the demo files for the jQuery accordion style menu
If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.
Comments
Wow, this is great Ryan. I’ve been battling with the jquery ui implementation for quite some time, and I couldn’t for the life of me figure out what could possibly be so hard when all I’ve wanted is exactly what you’ve done here. Thank you! Going up on the littleshoot.org site very soon now.
-Adam
@adam Glad to hear it worked for you. You will have to let me know when its online so I can check it out.
@adam – Nice glad to see it in action! Like the site, cool application. I hadn’t heard of Little Shoot today but I will have to pass it on.
Glad you like it. We’re actually about to issue a major new release that’s the first true p2p browser plugin ever built (NPAPI, ActiveX). If you feel like taking it for a spin, it’s at:
Hi Ryan – how easy would it be to open the first accordion on entry to the form? (I’m using it for a news list)
Many thanks
Neil
@Neil – It is super easy to open the first accordion item on load. I have created some modified code to do so and it can be downloaded by clicking:
http://www.stemkoski.com/downloads/jquery-accordion-menu-open.zip
I set it up so that it is possible to choose which DIV to open first. Basically all you need to do is add the id=”open” to whatever DIV you want to open and then add this as the last line in your JavaScript:
$(“#open”).trigger(‘click’);
That will simulate a click on the one assigned with the id open after all items are shut. The example in the new zip file has it all working. Feel free to contact me if you have any problems.
Awesome! Awesome! Awesome! I’ve been banging my head against a wall using the jquery ui accordion and just couldn’t understand why so much code was needed for an accordion. I’m using it right now but would it be possible to have the button of the accordion that is open be different from the other buttons? For example, the closed accordion’s buttons would be black and the open accordion’s button would be red. Don’t know how difficult that would be so don’t waste your time if it’s very difficult. Thanks again!!!
I read your article “Change the Style of DIV on Mouseover with jQuery” and based on that I think I may have come up with a solution to my problem of changing the class of the accordion button depending on whether or not its content is open. This code may very well be wrong but I replaced…
$('div.accordionButton').click(function() {
$('div.accordionContent').slideUp('normal');
$(this).next().slideDown('normal');
});
with
$('div.accordionButton').click(function() {
$('div.accordionContent').slideUp('normal');
$(this).next().slideDown('normal');
$("div.accordionButtonSelected").removeClass().addClass("accordionButton");
$(this).removeClass().addClass("accordionButtonSelected");
});
I’ve tested it in IE7, IE6, Firefox, Chrome, Safari and it seems to work but I guess that doesn’t necessarily mean it’s right. Thanks for any advice you can give!
@Jermey Glad to see you got it figured out. That is basically how I would’ve suggested doing it anyway. Congrats on figuring it all out on your own. Hope it works well for you.
Great tutorial!
Excited to see the google API being used (which everybody should do!).
How would you make it a “fixed” height?
(So it dosent use the invidual height on each “content”?)
@Marco HJ This is actually pretty easy to do. All you need to do is give the class .accordionContent a height in the CSS. So your new CSS would look something like:
#wrapper { width: 800px; margin-left: auto; margin-right: auto; } .accordionButton { width: 800px; float: left; background: #003366; border-bottom: 1px solid #FFFFFF; cursor: pointer; } .accordionContent { width: 800px; height: 300px; //SET TO WHATEVER HEIGHT YOU WANT TO USE float: left; background: #95B1CE; display: none; }
Thanks so much Ryan! You saved me a lot of time!
I’d like ask one more question: Is it possible to have a behaviour that when you click on the button with the content already open this causes the content to close again (without another content opening)?
Best regards
Helge
@Helge I just got this working… pretty simple… lets see… starting after the ready statement and the part where you hide:
$(“div.accordionButton”).click(function() {
if ($(this).is(“.accordionButtonSelected”)){
$(“div.accordionContent”).slideUp(“normal”);
} else {
$(“div.accordionContent”).slideUp(“normal”);
$(this).next().slideDown(“normal”);
$(“div.accordionButtonSelected”).removeClass().addClass(“accordionButton”);
$(this).removeClass().addClass(“accordionButtonSelected”);
}
});
Basically you look for the “selected” class and then handle it differently. Specifically, you close it and nothing else!
I’m a hack so there’s prolly some smarty pants over here that can do it in like 2 characters or something… anyway, works for me!
whee!!
Thanks to Ryan for the tutorial and Jeremy Thompson for the “selected” trick!!!!
-Fever
oh yeah… if yr tweaking the “selected” style… you can remove it on close by:
$(”div.accordionButton”).click(function() {
if ($(this).is(”.accordionButtonSelected”)){
$(”div.accordionContent”).slideUp(”normal”);
$(this).removeClass().addClass(“accordionButton”);
} else {…
note the new “$(this).removeClass().addClass(“accordionButton”);”
this way you can have an “on” bg color and an “off” bg color (if you just used my 1st example, the button would always be “on”)
again, above disclaimer still applies… hack, prolly a slicker way, etc.
Thanks for the tut.
I wounder if we can add a script to allow the opened content to close when clicking on the same button.
Regards,,
Moosa
@Bobby Fever – Thanks for putting that tutorial together. The technique you used was what I was going to do for Helge but I just hadn’t had the time.
@Helge – Looks like Bobby beat me to it.
@Mossa – You were just a couple hours early. If I would’ve approved the comment from bobby last night you would’ve been set.
Thanks for a nicely written example! I was wondering if it’s possible to get this easyly working in IE 6? In the demo it doesn’t seem to hide everything correctly in this damn relic browser.
@iisakki I had to make it work in IE6 on a project and I changed the float: left; in the .accordionContent to display: inline-block; and it solved the problem. I took that out when making the tutorial because in some instances it bugs out in IE7.
@Bobby @Helge – Here is the way I would make the open element close without re-opening:
$(document).ready(function() { //ACCORDION BUTTON ACTION $('div.accordionButton').click(function() { if($(this).next().is(':visible')) { $('div.accordionContent').slideUp('normal'); } else { $('div.accordionContent').slideUp('normal'); $(this).next().slideDown('normal'); } }); //HIDE THE DIVS ON PAGE LOAD $("div.accordionContent").hide(); });
This is a great wee script as it keeps things very simple. My only problem is that sometimes the content flickers as a div is opening or closing. This does not happen all the time but it is very noticeable when it does! I have images as part of the accordion content. I’d appreciate any help or suggestions.
@Gary B I’ve noticed a flicker if you have any type of padding inside your .accordionContent box. Not sure if that’s what’s causing your problem, just something I’ve noticed.
This is so insanley simple I’m kicking myself for not trying something similiar instead of using all these uber bloated accordian scripts. Like many here I just need a clean lightweight method for creating a simple accordian. This fits the bill perfect.
Hi!
thanks for this tutorial, very helpfull indeed!
I have just started out playing arond with Jquery and i wanted to ask for some help.
i was able to integrate an accordion menu with my wordpress theme
as so:
Portfolio
now all i really need to do is add a css class ‘active’ to the accordionButton which contains the active category(category being displayed).
now i dont know if you are familiar with wordpress at all, but that part of the code wp_list_categories creates an UL of category links.
since i assigned one category under each div of the accordion, i need to create a style that identifies where the current category is.
i hope i was able to explain myself!
any insights are greatly appreciated!
thanks,
pvf
re: pvf:
WordPress has a built-in CSS class for currently selected pages.
If you search the wordpress codex for .current_page_item you should find it.
Basically wordpress automatically appends this class to the currently selected page, so you should be able to style this for your accordian with CSS.
@Gary B: check the CSS file: the “.accordionContent” div should be display: none;
.accordionContent {
width: 800px;
float: left;
background: #95B1CE;
display: none;
}
So thankful to come across this thread. Like others, I’ve been driving myself bonkers with the UI scripts. I changed the click event to mouseover so sections expand on hover. The only problem is that when you mouse off of the menu, the currently expanded section remains expanded. Could someone help a javascript novice and explain how to make the entire menu collapse to its original state on mouseout? Thanks in advance!
@Corey – This is pretty easy to do. On your mouseout function run this code:
$("div.accordionContent").hide();
It will collapse all div elements with the class accordionContent.
@Ryan – I really appreciate it. Almost got it. Below is the code I added, and the content areas now collapse immediately upon mousing out of the buttons (preventing access to the content areas). As I mentioned I’m brand-spanking new with javascript so this may look completely laughable. Any help would be appreciated. Thanks!
$(document).ready(function() {
//ACCORDION BUTTON ACTION
$(‘div.accordionButton’).mouseover(function() {
if($(this).next().is(‘:visible’)) {
$(‘div.accordionContent’).slideUp(‘normal’);
} else {
$(‘div.accordionContent’).slideUp(‘normal’);
$(this).next().slideDown(‘normal’);
}
});
$(‘div.leftnav’).mouseout(function() {
$(“div.accordionContent”).slideUp(‘normal’);
});
//HIDE THE DIVS ON PAGE LOAD
$(“div.accordionContent”).hide();
});
Many thanks for making this available. Is there a way for an open element to be open right from the start without sliding down at the beginning? Thanks in advance!
@Ryan – Cheers for your litle snippet of code to close an open tab, works a treat and saved me lots of time trying to hack a solution myself.
Thanks for this stupidly simple script!!! I’ve got a question, because the thing I want to do is a little weird.
What I need is for the according to open when you hover over the .accordionButton When you mouse out it stays open though.
But then the only way to close the according is if you CLICK on either the open button, or another one.
Does that make sense? I am new to javascript, so I have no clue what I’m doing.
Hi Tamer, That question was answered by Bobby in the comments above. Give his solution a try and if you can’t get it working let us know.
Hi Folks. Thanks for the great script. This is exactly what I needed. I have a question and hopefully it is easy to solve. I basically just want to customize the script so that when you click on one section, the section that was previously open closes first and then the section that you clicked opens afterwards. As of now, they open and close at the same time. Is there someway to delay the opening of the new section until after the first section closes?
Does anyone know how to do this? I am pretty much a beginner with javascript.
I appreciate any help in advance.
Thanks a bunch.
Thank you so very much for this script. It works out perfectly for my site, where I really want users to have an interactive visiting experience — it truly allows users to see only the content they request!
I have one question — is there a simple way to style the “accordionButton” class to have a hover color?
Thanks again!
@Drew you could use the CSS hover property to add rollover styles to the .accordionButton class or you could use jQuery to modify the class of the DIV on mouseover.
Check here for more help using jQuery to change the style of a DIV on mouseover:
http://www.stemkoski.com/change-the-style-of-div-on-mouseover-with-jquery/
You can make this better by not using inline styles … and instead using proper document structure:
Section 1 Title
Content 1
Section 2 Title
Content 2
Section 3 title
Content 3
And alter your javascript to:
$(document).ready(function() {
//ACCORDION BUTTON ACTION
$('h2').click(function() {
$('p').slideUp('normal');
$(this).next().slideDown('normal');
});
//HIDE THE DIVS ON PAGE LOAD
$("p").hide();
@Lacy you make a good point. It could be simplified even further. My goal was to create something that could be dropped into an existing website and work without the need to understand the JavaScript. A solution like you provided would work assuming the user didn’t have any other H2 or P elements on the page, if they did, they would get some undesired results and users with limited JavaScript knowledge may not know how to fix the problem! Also, just a technical note, this doesn’t actually use inline styles it uses an external stylesheet. (Inline Style Definition: http://webdesign.about.com/od/css/g/bldefinlinestyl.htm | http://webdesign.about.com/od/beginningcss/qt/tipcssinlinesty.htm)
Hi,
Thanks for the great script.
Is there a way to make the sub-menu stay open if the user is browsing that specific category?
The sub-menu would also close if the user went to another category and the newly chosen category would open.
I hope this makes sense.
@Justin I am not quite sure what you are talking about. Could you try to explain it a little more for us?
Sorry about that.
Say I have 3 sub-menus:
Once I click on link 1 in menu 1. I want that sub-menu to stay open until I click on another sub-menu link in one of the other 2 menus.
This is the site I am working on:
I would prefer a class to be added by the script since this menu will be added and amended dynamically.
I have a similar question to Justin, I think –
I’m trying to modify your javascript so that I can have multiple sections of the accordion expanded at the same time.
Commenting out this line in the “else” statement:
$(‘div.accordionContent’).slideUp(‘normal’);
achieves that — the problem is, when I click to close any of the accordion sections, every section closes, not just the one I clicked on.
Any ideas?
Thanks again for your help Ryan! This tutorial rocks.
@Drew, try something like this:
$(document).ready(function() { //ACCORDION BUTTON ACTION $('div.accordionButton').click(function() { if($(this).next().is(':visible')) { $(this).next().slideUp('normal'); } else { $(this).next().slideDown('normal'); } }); //HIDE THE DIVS ON PAGE LOAD $("div.accordionContent").hide(); });
This will allow multiple elements to be open at once. Clicking on the header of an open element will close it. When you use $(“div.accordionContent”).hide(); this will hide all DIV elements with the class accordionContent you can also use $(“.accordionContent”).hide();to do the same thing. You can access each element based on the order it appears in the HTML by doing something like $(“div.accordionContent”).eq(0).hide(); which would be the first element. You can also use $(“div.accordionContent:eq(0)”).hide(); to do the same thing. jQuery often has many routes to the same result. Using $(this).next().slideUp(‘normal’); tells jQuery to close the element that follows the current element in the document. The Stupid Simple jQuery Accordion Menu relies on document order to function. It assumes that each header element is followed by a body element which needs to be opened or closed.
Hope this helps you guys out.
Thanks for this tutorial. Even a noob like me was able to implement this accordion on his site.
Is there a way to make the page scroll to the top of the opened accordion item automaticly (when clicked only, not on page load)?
I got a shorter item under a long item so when the long one closes and the short one opens then the short one vanishes and I have to scroll up to see it. So a auto scroll to the top of the newly opened item would be awesome.
Hi Ryan,
This works great for keeping all of the elements open, but what about having one element open at a time?
I converted the code to work with an unordered list.
Will this cause issues?
Here is my css and java I am using…
/*Menu CSS*/
* {margin: 0; padding: 0;}
a:focus {outline:none;}
#menu_container {
background:#fff url(../imgs/global/right.jpg) top left repeat-x;
border:1px solid #B2C397;
padding:2px 8px 6px 8px;
position:relative;
list-style:none;
width:204px;
float:left;
left:15px;
}
#menu li{
list-style:none;
}
ul#menu {
margin:0px 0px 0px 0px;
list-style:none;
padding:0px;
}
ul#menu a {
text-decoration:none;
cursor:pointer;
display:block;
}
ul#menu .active {
padding:5px 7px 5px 8px;
margin:4px 0px 0px 0px;
list-style-type:none;
letter-spacing:.2px;
background:#3F85C1;
position:relative;
font-weight:bold;
text-align:left;
font-size:12px;
cursor:pointer;
display:block;
color:#ffffff;
width:188px;
}
ul#menu .active:hover {
padding:5px 7px 5px 8px;
margin:4px 0px 0px 0px;
list-style-type:none;
letter-spacing:.2px;
background:#3F85C1;
position:relative;
font-weight:bold;
text-align:left;
font-size:12px;
cursor:pointer;
display:block;
color:#ffffff;
width:188px;
}
ul#menu li a {
padding:5px 7px 5px 8px;
margin:4px 0px 0px 0px;
list-style-type:none;
letter-spacing:.2px;
background:#E7EEC7;
position:relative;
font-weight:bold;
text-align:left;
font-size:12px;
cursor:pointer;
display:block;
color:#006699;
width:188px;
}
ul#menu li a:hover {
padding:5px 7px 5px 8px;
margin:4px 0px 0px 0px;
list-style-type:none;
letter-spacing:.2px;
background:#59A1DE;
position:relative;
font-weight:bold;
text-align:left;
font-size:12px;
cursor:pointer;
display:block;
color:#ffffff;
width:188px;
}
ul#menu li ul li a {
background:#F5F9E4 url(../imgs/global/nav_up.png) top left no-repeat;
background-position:6px 4px;
padding:5px 7px 5px 26px;
margin:2px 0px 0px 0px;
text-decoration:none;
font-weight:bold;
text-align:left;
font-size:12px;
display:block;
color:#0259A1;
width:170px;
}
ul#menu li ul li a:hover {
background:#E7EEC7 url(../imgs/global/nav_over.png) left no-repeat;
background-position:6px 4px;
padding:5px 7px 5px 26px;
margin:2px 0px 0px 0px;
text-decoration:none;
font-weight:bold;
text-align:left;
font-size:12px;
display:block;
color:#0259A1;
width:170px;
}
/*Menu Java*/
$(document).ready(function() {
//Controls accordion category (ul#menu li a) action.
$(‘ul#menu>li>a’).click(function() {
$(‘ul#menu li ul’).slideUp(‘fast’);
$(this).next().slideDown(‘fast’);
});
//Hide the options on page load.
$(“ul#menu li ul”).hide();
$(“ul#menu .submenu_active”).show();
});
Hi,
Sorry Ryan! I think I thanked Drew as the author of the tut. So Thanks Ryan. It was and still is a great tut.
I was writing a reply to Justin and I think I timed-out and lost everything I have typed. Then I thought the replies are moderated until I sent that sorry message. I am going to try again.
So Justin… Here is the html layout if you want to do it with ULs:
Button 1
Button 2
The JQuery code
1. For the header click function:
$(‘.accordionButton’).click(function()
{
if($(this).next().is(‘:visible’))
{
$(‘.accordionContent’).slideUp(‘normal’);
}
else
{
$(‘.accordionContent’).slideUp(‘normal’);
$(this).next().slideDown(‘normal’);
}
});
Very simple, as suggested by Drew.
2. The links click function:
$(“.links”).click(function(){
if ($(this).is(“.activeLink”)) //already active link
{
return false;
}
else
{
$(“.activeLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“activeLink”);
return false;
}
});
Then you set your .activeLink class style in your CSS.
3. For the Hover function :
$(“.linkds”).hover(function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“.hoveredLink”);
}
}, //and yeah! it’s not a semi-colon
function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
}
});
And then you have also to set your style for the .hoveredLink class in your CSS
4. Adding automatic triggers:
$(“#open”).trigger(‘click’)
$(“.links:first”).trigger(‘click’);
0. Put it all together :
This should have been the first point.
a) prepare your html
b) combine your JQuery function
This is is the end result :
$(document).ready(function(){
//Button click function
$(‘.accordionButton’).click(function()
{
if($(this).next().is(‘:visible’))
{
$(‘.accordionContent’).slideUp(‘normal’);
}
else
{
$(‘.accordionContent’).slideUp(‘normal’);
$(this).next().slideDown(‘normal’);
}
});
//Links click function
$(“.links”).click(function(){
if ($(this).is(“.activeLink”)) //already active link
{
return false;
}
else
{
$(“.activeLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“activeLink”);
return false;
}
});
//Links hover function
$(“.links”).hover(function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“.hoveredLink”);
}
}, //and yeah! it’s not a semi-colon
function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
}
});
//Automatic triggers
$(“#open”).trigger(‘click’)
$(“.links:first”).trigger(‘click’);
}); //closes the document.ready function
c) Now set your CSS styles for these classes :
.accordionContent
.accordionButton
.hoveredLink
.activeLink
.links
Final notes :
a. For triggers, you can give the “open” id in your html to the header you want to load first. You can also do the same for the link, but it has to be inside the header you want to load or acivate.
b. You will have to play with your css to make sure you get rid of the gap left between header and the links (due to the ul.accordion content.
c. Users will have to click on the header before getting to click on the link, unless you trigger the click inside the click action of the header. But this would be tricky and hard to code because a trigger must come after the function it calls.
Good Luck! Hope this will help.
This is a repost because the html code did not show up.
So Justin… Here is the html layout if you want to do it with ULs:
Button 1
Button 2
The JQuery code
1. For the header click function:
$(‘.accordionButton’).click(function()
{
if($(this).next().is(‘:visible’))
{
$(‘.accordionContent’).slideUp(‘normal’);
}
else
{
$(‘.accordionContent’).slideUp(‘normal’);
$(this).next().slideDown(‘normal’);
}
});
Very simple, as suggested by Drew.
2. The links click function:
$(“.links”).click(function(){
if ($(this).is(“.activeLink”)) //already active link
{
return false;
}
else
{
$(“.activeLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“activeLink”);
return false;
}
});
Then you set your .activeLink class style in your CSS.
3. For the Hover function :
$(“.linkds”).hover(function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“.hoveredLink”);
}
}, //and yeah! it’s not a semi-colon
function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
}
});
And then you have also to set your style for the .hoveredLink class in your CSS
4. Adding automatic triggers:
$(“#open”).trigger(‘click’)
$(“.links:first”).trigger(‘click’);
0. Put it all together :
This should have been the first point.
a) prepare your html
b) combine your JQuery function
This is is the end result :
$(document).ready(function(){
//Button click function
$(‘.accordionButton’).click(function()
{
if($(this).next().is(‘:visible’))
{
$(‘.accordionContent’).slideUp(‘normal’);
}
else
{
$(‘.accordionContent’).slideUp(‘normal’);
$(this).next().slideDown(‘normal’);
}
});
//Links click function
$(“.links”).click(function(){
if ($(this).is(“.activeLink”)) //already active link
{
return false;
}
else
{
$(“.activeLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“activeLink”);
return false;
}
});
//Links hover function
$(“.links”).hover(function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“.hoveredLink”);
}
}, //and yeah! it’s not a semi-colon
function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
}
});
//Automatic triggers
$(“#open”).trigger(‘click’)
$(“.links:first”).trigger(‘click’);
}); //closes the document.ready function
c) Now set your CSS styles for these classes :
.accordionContent
.accordionButton
.hoveredLink
.activeLink
.links
Final notes :
a. For triggers, you can give the “open” id in your html to the header you want to load first. You can also do the same for the link, but it has to be inside the header you want to load or acivate.
b. You will have to play with your css to make sure you get rid of the gap left between header and the links (due to the ul.accordion content.
c. Users will have to click on the header before getting to click on the link, unless you trigger the click inside the click action of the header. But this would be tricky and hard to code because a trigger must come after the function it calls.
Good Luck! Hope this will help.
So Justin… Here is the html layout if you want to do it with ULs:
Sorry again guys!
Button 1
Button 2
The JQuery code
1. For the header click function:
$(‘.accordionButton’).click(function()
{
if($(this).next().is(‘:visible’))
{
$(‘.accordionContent’).slideUp(‘normal’);
}
else
{
$(‘.accordionContent’).slideUp(‘normal’);
$(this).next().slideDown(‘normal’);
}
});
Very simple, as suggested by Drew.
2. The links click function:
$(“.links”).click(function(){
if ($(this).is(“.activeLink”)) //already active link
{
return false;
}
else
{
$(“.activeLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“activeLink”);
return false;
}
});
Then you set your .activeLink class style in your CSS.
3. For the Hover function :
$(“.linkds”).hover(function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“.hoveredLink”);
}
}, //and yeah! it’s not a semi-colon
function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
}
});
And then you have also to set your style for the .hoveredLink class in your CSS
4. Adding automatic triggers:
$(“#open”).trigger(‘click’)
$(“.links:first”).trigger(‘click’);
0. Put it all together :
This should have been the first point.
a) prepare your html
b) combine your JQuery function
This is is the end result :
$(document).ready(function(){
//Button click function
$(‘.accordionButton’).click(function()
{
if($(this).next().is(‘:visible’))
{
$(‘.accordionContent’).slideUp(‘normal’);
}
else
{
$(‘.accordionContent’).slideUp(‘normal’);
$(this).next().slideDown(‘normal’);
}
});
//Links click function
$(“.links”).click(function(){
if ($(this).is(“.activeLink”)) //already active link
{
return false;
}
else
{
$(“.activeLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“activeLink”);
return false;
}
});
//Links hover function
$(“.links”).hover(function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
$(this).removeClass().addClass(“.hoveredLink”);
}
}, //and yeah! it’s not a semi-colon
function(){
if ($(this).is(“.activeLink”)) //link is already active
{
return false;
}
else
{
$(“.hoveredLink”).removeClass().addClass(“links”);
}
});
//Automatic triggers
$(“#open”).trigger(‘click’)
$(“.links:first”).trigger(‘click’);
}); //closes the document.ready function
c) Now set your CSS styles for these classes :
.accordionContent
.accordionButton
.hoveredLink
.activeLink
.links
Final notes :
a. For triggers, you can give the “open” id in your html to the header you want to load first. You can also do the same for the link, but it has to be inside the header you want to load or acivate.
b. You will have to play with your css to make sure you get rid of the gap left between header and the links (due to the ul.accordion content.
c. Users will have to click on the header before getting to click on the link, unless you trigger the click inside the click action of the header. But this would be tricky and hard to code because a trigger must come after the function it calls.
Good Luck! Hope this will help.
Sorry againe guys. I was trying to find out a way to show up the html code for the post above but could not. So I decided to put a small mistake in the code so that the browser can show it. Just remove the * character and replace the # by your target link.
Here is the html code :
Button 1
Button 2
Button 3
Still did not work…
Sorry againe guys. I was trying to find out a way to show up the html code for the post above but could not. So I decided to put a small mistake in the code so that the browser can show it. Just replace the leading * by
*li class=”accordionButton”*>Button 1
*li class=”accordionContent”*>
*ul class=”ListOfLinks”*>
*li class=”links”*>Link 1
*li class=”links”*>Link 2
*li class=”links”*>Link 3
*li class=”links”*>Link 4
*/ul*>
*/li*>
*li class=”accordionButton”*>Button 2
*li class=”accordionContent”*>
*ul class=”ListOfLinks”*>
*li class=”links”*>Link 1
*li class=”links”*>Link 2
*li class=”links”*>Link 3
*li class=”links”*>Link 4
/ul*>
*/li*>
*li class=”accordionButton”*>Button 3
*li class=”accordionContent”*>
*ul class=”ListOfLinks”*>
*li class=”links”*>Link 1
*li class=”links”*>Link 2
*li class=”links”*>Link 3
*li class=”links”*>Link 4
*/ul*>
*/li*>
*/ul*>
Thanks for the Patience… Here is the HTML code for the previous reply :
(ul id=”Wraper”)(!– The Full Menu has to be a UL–)
(li id=”open” class=”accordionButton”)Tâches de routine(/li)
(li class=”accordionContent”)
(ul class=”ListOfLinks”)
(li class=”links”)(a href=”#”)Link 1(/a)(/li)
(li class=”links”)(a href=”#”)Link 2(/a)(/li)
(li class=”links”)(a href=”#”)Link 3(/a)(/li)
(li class=”links”)(a href=”#”)Link 4(/a)(/li)
(/ul)
(/li)
(/ul)
Just replace the () characters by the correct ones. I think I finally got it…
Awesome article. Im glad I found this. It works perfect. Is it possible to get one of them active (already showing) when the page loads?
@Bryan – It is super easy to open the first accordion item on load. I have created some modified code to do so and it can be downloaded by clicking:
http://www.stemkoski.com/downloads/jquery-accordion-menu-open.zip
I set it up so that it is possible to choose which DIV to open first. Basically all you need to do is add the id=”open” to whatever DIV you want to open and then add this as the last line in your JavaScript:
$(”#open”).trigger(’click’);
That will simulate a click on the one assigned with the id open after all items are shut. The example in the new zip file has it all working. Feel free to contact me if you have any problems.
There are other ways to do this but this is an easy one.
Hello Ryan,
can you please help me?
i want to create a condition in which it can detect if the accordionContent is slide down.
Example. if($(this).next(‘div.accordionContent’)).is(slideDown){
}
else{
}
But im just a newbie in JQuery.
Thanks…
Hey Ryan,
I already got the logic… thank you very much!
var $j = jQuery.noConflict();
$j(document).ready(function() {
$j(‘div.accordionButton’).click(function() {
if($j(this).next().is(‘:visible’))
{
$j(‘div.accordionContent’).slideUp(‘fast’);
$j(‘div.accordionTitle1′).text(“Hide”);
}
else
{
$j(‘div.accordionTitle1′).text(“Hide”);
$j(‘div.accordionContent’).slideUp(‘fast’);
$j(this).next().slideDown(‘fast’);
$j(‘div.accordionTitle1′,this).text(“Learn More”);
}
});
$j(“div.accordionContent”).hide(“fast”);
$j(‘div.accordionTitle1′).text(“Hide”);
});
Ryan, thanks so much for this simple script! I agree with you that using divs instead of lists makes the thing simpler to integrate into an existing site. I spent the past week searching for an accordion that I can understand (I’m a total JS newbie), yours does the job perfectly. I need to figure out how to modify the speed, but that’s just a minor tweak. Thanks again!
Ryan, thanks so much for this simple script! I agree with you that using divs instead of lists makes the thing simpler to integrate into an existing site. I spent the past week searching for an accordion that I can understand (I’m a total JS newbie), yours does the job perfectly. I need to figure out how to modify the speed, but that’s just a minor tweak.
Another thing I’m trying to get to work is a ’second level’, you know, one sub-accordion that opens within the main accordion? Would this be easy to implement?
Thanks again!
…just answered my first question: to change the speed of the slide, change “slideUp(‘normal’)” to “slideUp(‘fast’)” in all instances, same with “slideDown…”.
@Alan Earl A few people have had problems in IE6 although most the time it works. No idea what results in the problem but changing the
float: left;
to
display: inline-block;
Seems to fix it.
I hope someone can help ’cause obviously I’m missing something ;o/
The page I’m working on is at http://suewaitelangley.com/DrCTakeTwo/Take2.html
I’ve worked all afternoon on this problem…
I did manage to make the selected class work so that my images are changing (blue to orange on click…THANKS)
BUT…
I need to add a hover function (when you hover over the blue button it should turn orange BEFORE clicking when it will stay orange and expand)
AND…
I need to be able to click on an orange button (the content is expanded) and have it close the content and turn back to blue.
From all I’ve read both are possible but no matter how I’ve messed with the code I cannot get these functions to work.
HELP!
My code right now is…
$(document).ready(function() {
/********************************************************************************************************************
SIMPLE accordion STYLE MENU FUNCTION
********************************************************************************************************************/
$(‘div.accordionButton’).click(function() {
$(‘div.accordionContent’).slideUp(‘normal’);
$(this).next().slideDown(‘normal’);
$(“div.accordionButtonSelected”).removeClass().addClass(“accordionButton”);
$(this).removeClass().addClass(“accordionButtonSelected”);
});
/********************************************************************************************************************
CLOSES ALL DIVS ON PAGE LOAD
********************************************************************************************************************/
$(“div.accordionContent”).hide();
});
Thanks so much for all of your help. Hope someone sees this!
jquery
var $j = jQuery.noConflict();
$j(document).ready(function() {
/********************************************************************************************************************
SIMPLE ACCORDIAN STYLE MENU FUNCTION
********************************************************************************************************************/
$j(‘div.accordionButton’).click(function() {
/* Check Accordion if Visible */
if($j(this).next().is(‘:visible’))
{
$j(‘div.accordionContent’).slideUp(‘fast’);
$j(‘div.accordionTitle1′).text(“Learn More”);
$j(‘div.accordionImage’).css(‘background-image’,'url(style/images/check.png)’);
}
else
{
$j(‘div.accordionTitle1′).text(“Learn More”);
$j(‘div.accordionImage’).css(‘background-image’,'url(style/images/check.png)’);
$j(‘div.accordionContent’).slideUp(‘fast’);
$j(this).next().slideDown(‘fast’);
/* Check selected accordiontitle to text hide */
$j(‘div.accordionTitle1′,this).text(“Hide”);
$j(‘div.accordionImage’,this).css(‘background-image’,'url(style/images/close.png)’);
}
});
/********************************************************************************************************************
CLOSES ALL DIVS ON PAGE LOAD
********************************************************************************************************************/
$j(“div.accordionContent”).hide(“fast”);
/********************************************************************************************************************
SET div to text HIDE
********************************************************************************************************************/
$j(‘div.accordionTitle1′).text(“Learn More”);
$j(‘div.accordionImage’).css(‘background-image’,'url(style/images/check.png)’);
});
html
Button 1 Content
Content 1Long Example
Button 2 Content
Content 2Medium Example
Button 3 Content
Content 1Short Example
Button 4 Content
Content 4Extra Long Example
Hope it can help u! it will switch check/wrong picture per accordion click.
Thanks so much for the code! Now a second click is closing the content area…but…now my buttons are not changing from blue to orange. I replaced the check and close .pngs with my image names (announcement.png and newselected.png respectively) in your code. But my buttons stay blue. This code from one of the top posts worked to change the class of my buttons to change the background but I don’t know if or how it should be integrated.
What did I miss?
Thanks again for solving my need to close the content areas. You are too smart!
UPDATE
So now I have the button turning orange when clicked…
AND on the second click the content is sliding up! Yeah!
BUT the selected class does not revert to the blue button UNTIL I click another button. How can I combine the second click that hides the content with the switch back to the blue button…in other words if all content is hidden…all buttons should be blue.
Thanks…almost got it thanks to all of your help.
Hi everybody, I was trying to incorporate some fading-in and out, I thought something like
$(this)(‘div.accordionContent’).fadeIn(’slow’);
withing the ‘else’ statement might do the job, but unfortunately it doesn’t (and as probably everybody can tell I have close to no clue about JavaScript). Any ideas?
Andreas
if($j(this).next().is(’:visible’))
{
$j(’div.accordionContent’).slideUp(’fast’);
$j(’div.accordionTitle1′).text(”Learn More”);
$j(’div.accordionImage’).css(’background-image’,’url(style/images/check.png)’);
}
This code is, if all content is hidden.
Hehehehe…. Try & Try until you succeed!
OK…I guess I’m confused with the labels…
div.accordionContent (I have this div label and understand what you’re doing.
div.accordionTitle1 (I think this div label refers to the selected div which in my case is div.accordionButtonSelected)
BUT it’s the div.accordionImage I’m really confused on…not sure what you’re referring to.
I have div.accordionButton (blue background)
and I have div.accordionButtonSelected (orange background)
and I changed the url for the image you have as check.png to my url for the blue button
I put a text file of my js file at http://suewaitelangley.com/DrCTakeTwo/JS/CollapsibleAccordion.txt
AND my css file is at http://suewaitelangley.com/DrCTakeTwo/Take2.css
Obviously I’m not the js queen…but I’m pretty good at following code once it’s working and learning for future from there. THANKS so much for all of your patience and help. Sue
jquery
var $j = jQuery.noConflict();
$j(document).ready(function() {
/********************************************************************************************************************
SIMPLE ACCORDIAN STYLE MENU FUNCTION
********************************************************************************************************************/
$j(‘div.accordionButton’).click(function() {
/* Check Accordion if Visible */
if($j(this).next().is(‘:visible’))
{
$j(‘div.accordionContent’).slideUp(‘fast’);
$j(‘div.accordionTitle1′).text(“Learn More”);
$j(‘div.accordionImage’).css(‘background-image’,'url(style/images/check.png)’);
}
else
{
$j(‘div.accordionTitle1′).text(“Learn More”);
$j(‘div.accordionImage’).css(‘background-image’,'url(style/images/check.png)’);
$j(‘div.accordionContent’).slideUp(‘fast’);
$j(this).next().slideDown(‘fast’);
/* Check selected accordiontitle to text hide */
$j(‘div.accordionTitle1′,this).text(“Hide”);
$j(‘div.accordionImage’,this).css(‘background-image’,'url(style/images/close.png)’);
}
});
/********************************************************************************************************************
CLOSES ALL DIVS ON PAGE LOAD
********************************************************************************************************************/
$j(“div.accordionContent”).hide(“fast”);
/********************************************************************************************************************
SET div to text HIDE
********************************************************************************************************************/
$j(‘div.accordionTitle1′).text(“Learn More”);
$j(‘div.accordionImage’).css(‘background-image’,'url(style/images/check.png)’);
});
html
[body]
[div id="wrapper"]
[div class="accordionButton" id="open"]Button 1 Content [div class="accordionImage"][/div][div class="accordionTitle1"][/div][/div]
[div class="accordionContent"]Content 1[br /][br /][br /][br /][br /][br /][br /][br /]Long Example[/div]
[div class="accordionButton"]Button 2 Content [div class="accordionImage"][/div][div class="accordionTitle1"][/div][/div]
[div class="accordionContent"]Content 2[br /][br /][br /][br /][br /]Medium Example[/div]
[div class="accordionButton"]Button 3 Content [div class="accordionImage"][/div][div class="accordionTitle1"][/div][/div]
[div class="accordionContent"]Content 1[br /]Short Example[/div]
[div class="accordionButton"]Button 4 Content [div class="accordionImage"][/div][div class="accordionTitle1"][/div][/div]
[div class="accordionContent"]Content 4[br /][br /][br /][br /][br /][br /][br /][br /][br /][br /][br /][br /][br /][br /][br /][br /]Extra Long Example[/div]
[/div]
[div class="accordionImage" style="background-image: url(images/check.png); height: 100px; width:100px;"/]
[/body]
In my case i switch the two image. But then in your case you switch the background color right. Therefore the logic is still the same.
Hi everybody, I’m experiencing a very weird problem in Safari. I built a little site that contains flash content in each Accordion content level, and when opening the accordion one after another everything works well-BUT when e.g. going first to “audio” and then to “motion graphics”, the swf file doesn’t run properly. The weirdest thing is that I can’t reproduce it, on the laptop of my roommate everything is working (as it is in Firefox, too). Here’s the site: http://www.andreastretner.de
PLEASE, any help highly appreciated!!
Thanks & nice holidays to everybody,
Andreas
Just a follow up regarding my post above: I switched to the jQuery Accordion which worked better for my flash movies in Safari (actually, I’m now using an older version, the one by “bassistance.de” also uses divs for the mark up). So, all good, no need for help anymore.
Greets
Andreas
Stupid Simple Accordion indeed. Thanks a lot!
I read through most of the comments but I can’t seem to find the answer. How do you keep an accordion stay open upon page change? The opened accordion should be the one that the user previously clicked.
Thanks for this, I went through so many complex solutions to this before finally coming across this one which I could actually figure out.
Also, thanks for posting a way to have the menu close again on click.
Just what I was looking for!
Great script. Easy to use and practical. My kudos!
I have this scenario and I would like your help: when I click in a link in the content (that loads another page of the site), the same menu unfolds again. I would prefer though to avoid having the menu unfodling for a second time (to get rid of the animation when it reloads). Is it possible?
Thanks for the great script! anyone have a quick way to add a show/hide all button to this function? Trying to figure it out myself to no avail yet…
The easiest way would be to add something like this to the javascript section:
//ACCORDION BUTTON ACTION $('.hide').click(function() { $('div.accordionContent').slideUp('normal'); });
Then you can add a span or some other element with the class “hide” and when it is clicked it will slide up all open accordion panels.
<span class="hide">Hide all Panels</span>
Basically the Javascript code will execute anytime someone clicks and element with the class hide. It will then loop through all the DIV elements with the class accordionContent and close them if they are open. If you wish to open them all you would do the same thing except instead of using .slideUP in the jQuery you would use slideDown.
Thanks so much for this quick/easy solution. I’ll definitely be saving it in my “little bag ‘o tricks!”
Hi i think it’s better to use slideToggle instead of slideUp or slideDown.
Thanks for the simplicity.
$(document).ready(function() {
//ACCORDION BUTTON ACTION
$(‘div.accordionButton’).click(function() {
if($(this).next().is(‘:visible’)) {
$(this).next().slideToggle(‘normal’);
} else {
$(this).next().slideToggle(‘normal’);
}
});
//HIDE THE DIVS ON PAGE LOAD
$(“div.accordionContent”).hide();
});
Sorry, the solution is :
$(document).ready(function() {
//ACCORDION BUTTON ACTION
$(‘div.accordionButton’).click(function() {
$(‘div.accordionContent’).slideUp(‘normal’);
$(this).next().slideToggle(‘normal’);
});
//HIDE THE DIVS ON PAGE LOAD
$(“div.accordionContent”).hide();
});


I always like stupid simple scripts to use. Thanks.
Page bookmarked for future reference