A Simple and Beautiful jQuery Accordion Tutorial

A Simple and Beautiful jQuery Accordion Tutorial


A Simple and Beautiful jQuery Accordion Tutorial

Introduction

I was about running of ideas in tutorials, picking my own brain, and finally, I've almost forgotten the awesomeness of accordion. Yes, we will be creating a Accordion! Accordion has several characteristics:

  • Normally, the menu is displayed vertically (I have seen a horizontal one though)
  • Click on an item, it will expand its submenu and hide other submenu
  • Usually, an Accordion has indicators to show the state of the menu

So, yes, we will do that with the minimal amount of code, clean html and good looking images.

1. HTML

In this section, we use UL List to form the structure. The first level UL will be the navigation menu, and the second level UL that resides inside each first level UL's LI will be the submenu.

There is some rules over here about the classes and rel attribute, let me explain:

  • .popular, .category, .comment Classes in the anchor element (first level) are used for the styling of the menu.
  • Rel atribute in the anchor element (first level) is used by javascript to add and remove "selected state" aka change the menu image after it was clicked
  • .item class is required for each heading item
  • .last Class is used to remove border bottom for the last item
<ul id="accordion">
	<li>
		<a href="#" class="item popular" rel="popular">Popular Post</a>
		<ul>
			<li><a href="#">Popular Post 1</a></li>
			<li><a href="#">Popular Post 2</a></li>
			<li><a href="#" class="last">Popular Post 3</a></li>
		</ul>
	</li>
	<li>
		<a href="#" class="item category" rel="category">Category</a>
		<ul>
			<li><a href="#">Category 1</a></li>
			<li><a href="#">Category 2</a></li>
			<li><a href="#" class="last">Category 3</a></li>
		</ul>
	</li>
	<li>
		<a href="#" class="item comment" rel="comment">Recent Comment</a>
		<ul>
			<li><a href="#">Comment 1</a></li>
			<li><a href="#">Comment 2</a></li>
			<li><a href="#" class="last">Comment 3</a></li>
		</ul>
	</li>
</ul>

2. CSS

CSS is pretty simple, we are using two UL Lists. So, what we do is, style the first level UL, skin it with images, and after that, style the second UL List and hide it.

Have you heard about CSS Sprite? CSS Sprites are the preferred method for reducing the number of image requests. Combine your background images into a single image and use the CSS background-image and background-position properties to display the desired image segment. Yes, this is the image we are using for this tutorial:

CSS Sprite Menu Layout

And, if you wish to learn more about CSS, you can read my previous posts:

/* First Level UL List */
#accordion {
	margin:0;
	padding:0;	
	list-style:none;
}
	
	#accordion li {
		width:267px;
	}
	
	#accordion li a {
		display: block;
		width: 268px;
		height: 43px;	
		text-indent:-999em;
		outline:none;
	}
		
	/* Using CSS Sprite for menu item */
	#accordion li a.popular {
		background:url(menu.jpg) no-repeat 0 0;	
	}

	#accordion li a.popular:hover, .popularOver {
		background:url(menu.jpg) no-repeat -268px 0 !important;	
	}
		
	#accordion li a.category {
		background:url(menu.jpg) no-repeat 0 -43px;	
	}

	#accordion li a.category:hover, .categoryOver {
		background:url(menu.jpg) no-repeat -268px -43px !important;	
	}
		
	#accordion li a.comment {
		background:url(menu.jpg) no-repeat 0 -86px;	
	}

	#accordion li a.comment:hover, .commentOver {
		background:url(menu.jpg) no-repeat -268px -86px !important;	
	}
		
		
	/* Second Level UL List*/
	#accordion ul {
		background:url(bg.gif) repeat-y 0 0;
		width:268px;
		margin:0;
		padding:0;
		display:none;	
	}
		
		#accordion ul li {
			height:30px;
		}
			
		/* styling of submenu item */
		#accordion ul li a {
			width:240px;
			height:25px;
			margin-left:15px;
			padding-top:5px;
			border-bottom: 1px dotted #777;
			text-indent:0;
			color:#ccc;
			text-decoration:none;
		}

		/* remove border bottom of the last item */
		#accordion ul li a.last {
			border-bottom: none;
		}	

3. Javascript

There are two major sections in this javascript click event:

  • First section: Reset everything back to default. What it does, hide all the submenus and also reset all the arrow to default position.
  • Second section: Display the selected item and change the arrow direction

It gets a little bit tricky in resetting the arrow back to default position. I'm using for each method to loop thorugh the menu, grab its REL and and remove the classes. I think there are different ways to accomplish it. If you do know a better way, please let me know and I will ammend it.

	
$(document).ready(function () {
		
	$('#accordion a.item').click(function () {

		/* FIRST SECTION */
	
		//slideup or hide all the Submenu
		$('#accordion li').children('ul').slideUp('fast');	
		
		//remove all the "Over" class, so that the arrow reset to default
		$('#accordion a.item').each(function () {
			if ($(this).attr('rel')!='') {
				$(this).removeClass($(this).attr('rel') + 'Over');	
			}
		});
		
		/* SECOND SECTION */		
		
		//show the selected submenu
		$(this).siblings('ul').slideDown('fast');
		
		//add "Over" class, so that the arrow pointing down
		$(this).addClass($(this).attr('rel') + 'Over');			
	
		return false;

	});

	
});

Conclusion

Like this tutorials? You can express your gratitude by visiting my sponsors on the sidebar, bookmark it and help me to spread this tutorial to our friends! :) Thanks!

Author: Kevin Liew

Kevin Liew is a web designer and developer and keen on contributing to the web development industry. He loves frontend development and absolutely amazed by jQuery. Feel free to say hi to me, or follow @quenesswebblog on twitter.

Share the love

54 comments

bucabay
Wed, 7th October 2009
There are a few functionality issues such as clicking on the currently open item will close it and open it again. Clicking on a child, will close the parent etc. Other then that it is very nice. Reply
fanta
Sat, 2nd April 2011
exactly, how to fix it? Reply
sandeep
Wed, 25th May 2011
below is the complete solution for the current item close-open problem
<head>
<script language="javascript" type="text/javascript" src="jquery.min.js"></script>
<script language="javascript" type="text/javascript">

$(document).ready(function() {

$('.question').click(function()
{
$('.question').removeClass('active');

$('.content').slideUp('normal');

if($(this).next().is(':hidden') == true) {

$(this).addClass('active');

$(this).next().slideDown('normal');
}
});

$('.content').hide();

});

</script>

<style>

a {border:1px solid #000; display:block; height:25px; margin:0 0 5px 0}
.active {background:#000; color:#fff}
</style>


</head>

<body>

<div class="accordion">
<a class="question" href="#">test1</a>
<p class="content">text1</p>

<div style="clear:both"></div>

<a class="question" href="#">test2</a>
<p class="content">text2</p>

<div style="clear:both"></div>

<a class="question" href="#">test3</a>
<p class="content">text3</p>

<div style="clear:both"></div>

</div>




</body>


</html>
Reply
Tai Travis
Mon, 26th October 2009
I love the simplicity of it. I wasted my time trying implement the JQuery UI Accordian which is bloated and poorly written. Your simple efficient approach is giving me a solid place to expand from.
Couple pointers:
* JQuery is now v.1.3.2.
* The easing plugin appears to not being used by your script.
* The demonstration closes the accordion on page load while the example code does not. Please add this to the code above:
$(\'#accordion li\').children(\'ul\').hide();

Thanks again for being such a great resource. Cheers. Reply
kevin Admin
Tue, 1st December 2009
Thanks for suggestion. :) Reply
Patrizio Quatrini
Tue, 1st December 2009
Hello there, great tutorial but if I can, I\'d like suggest You to write \"display:none\" not inside CSS but in the js Code to let the list more accessible if the JS is disable. Thank You for reading. Reply
drizzy
Sun, 17th January 2010
is it possible for it to collapse more into sub heading as well?

So basically if you had a heading:

i.e.

> Major Attractions ‘you click that it drops down to’
> CN Tower ‘and when you click that it drops down
> ‘a short description of the CN tower’

is something like that possible ? Reply
Nic
Fri, 22nd January 2010
How do I get the links to work in the child ul currently by clicking these links the section just closes and does not goto the link. Reply
KIRAN
Fri, 12th March 2010
hi i am using jquery Collapsing menu
my Q is if on page load every time it get open 1st menu , but if i want to open any other den wht i can do
her isthe js for same
function initMenu() {
$('#menu ul').hide();
$('#menu ul:first').show();
$('#menu ul').hide();
$('#menu li a').click(
function() {
var checkElement = $(this).next();
alert(checkElement.id);
if((checkElement.is('ul')) && (checkElement.is(':visible'))) {
return false;
}
if((checkElement.is('ul')) && (!checkElement.is(':visible'))) {
$('#menu ul:visible').slideUp('normal');
checkElement.slideDown('normal');
return false;
}
}
);
}
$(document).ready(function() {initMenu();}); Reply
Tutorials99
Fri, 28th May 2010
good wok friend..
I found another site having top page rank professional tutorials.see link below,I hope its helpful

http://www.tutorials99.com Reply
ilz
Mon, 14th June 2010
The "tutorial" link on the demo page goes to the wrong tutorial, FYI. Reply
Phillie
Fri, 2nd July 2010
to get links to work, change return false;
to return; Reply
Chris
Thu, 20th October 2011
thanks Philly - good tip here.

Does anyone have the following problems:
Where when they click it makes their browser scroll to the left (to the limit of the site)?
Extreme padding around the li buttons? I cant find how to adjust the spacing Reply
Raghibsuleman
Fri, 16th July 2010
Thanks for Download jquery accordion Reply
reis
Thu, 22nd July 2010
is there a way to have this begin with all levels close? mine seems to be fully expanded when I first open the page. Reply
kevin Admin
Mon, 26th July 2010
Hi reis, I'm not sure what's the problem, but please refer to the demo, all the tabs are closed from the start. Reply
freelance writing jobs
Tue, 21st September 2010
Great post! Thanks for sharing! Reply
Simon
Tue, 12th April 2011
Your accordion has the jQuery slideUp/Down bug that makes the bottom of the accordion (or the content below) jump/bounce. Any way to fix this? Reply
Rob
Tue, 24th May 2011
It works, it works, it works! Thank you Reply
Rob
Mon, 18th April 2011
This works really well - thank you - but is there a way for the accordion to begin with one selected level open rather than all closed? Reply
Kevin Liew Admin
Mon, 18th April 2011
#accordion li.selected ul {display:block;}

add that line to your css file and put selected in the level that you want it to be displayed by default.

<ul id="accordion">
<li class="selected">
.......

try that Reply
Rob
Tue, 19th April 2011
Hi Kevin, I tried that but it does not seem to make a difference - the page still opens with the menu in the default closed position rather than opening with the menu expanded to display the relevant submenu item. Any ideas? Thank you Reply
Kevin Liew Admin
Tue, 3rd May 2011
oops, my bad. try this:

add this to the last line of css:

#accordion ul.selected {display:block !important}

then, put it to the first ul.

<ul class="selected">
Reply
Nathan
Tue, 26th April 2011
How do you make it so that when you click on the main button (popular post, catagory and comments) it would close. Right now the only way to close the slide down is to click on the sub menus. Reply
Kevin Liew Admin
Wed, 27th April 2011
Change this line to :

if ($(this).children('ul').is(':visible')) $(this).children('ul').slideDown('fast'); Reply
Matias
Sat, 30th April 2011
Thanks for this, it´s a great menu. But this is my first aproach to JavaScript, i don´t understand wich line has to be replaced Reply
Kevin Liew Admin
Tue, 3rd May 2011
oops, line 21. so, if the UL list is visible, it will not do the slide down again. Reply
Tyler
Sun, 15th April 2012
I see this code you included : [ if ($(this).children('ul').is(':visible')) $(this).children('ul').slideDown('fast'); ? ]
and i see that you said :oops, line 21.

But replacing line 21 with the code mentioned just breaks it. Can you list the full <script /> section with it included so that when you click on an already open section it will close? Or give a bit of instruction on doing so? Cheers! great post by the way! Reply
JB
Fri, 19th August 2011
I would like to know how to deploy the menus to open on mouse over and if one can have another menu to slide out of the submenus to the right. Reply
casey
Wed, 28th September 2011
The links did not work on this as well when I plugged it into wordpress. I fixed it by adding a conditional statement.

var $target = $(event.target);
if ( $target.is('ul li a') ) {
return true;
}else{
return false;
};

This allows a link to work if its a lower ul, if its an upper li however it causes the opening of the accordion. also had to add this to the beginning to make them all close:


$('#accordion li').children('ul').hide();
Reply
Paul
Wed, 23rd November 2011
casey, сould you share your css? Reply
msn
Mon, 31st October 2011
Is there a way for the accordion to begin with one selected level open rather than all closed? Tried using this #accordion ul.selected {display:block !important}

then, put it to the first ul.

<ul class="selected">

But not seems to be working Reply
Pavel
Wed, 23rd November 2011
I'm having difficulties adjusting the CSS, I have classes assigned to LI, not A as in your example. Is it possible to do it that way?
<li class="popular">
<a href="#" rel="popular">Popular Post</a>
<ul>
<li><a href="#">Popular Post 1</a></li>
<li><a href="#">Popular Post 2</a></li>
<li><a href="#" class="last">Popular Post 3</a></li>
</ul>
</li> Reply
Kevin Liew Admin
Thu, 24th November 2011
it is possible, the way you style it will be:

li.popular a {all the style for the label}
li.popular li a {you will need to clear all the style from the first line, it will get inherited}
Reply
Mark
Tue, 10th January 2012
Hi I'm a beginner. I got the menu working in my side but I don't understand how to use the selection function. When I put in a link at href and I click a item in the list, the menu goes back to his original position. How do I link my other pages to the navigation? Can anybody please explain it without showing only code? Thanks for helping. Reply
Kevin Liew Admin
Thu, 12th January 2012
Hi Mark, I have updated the tutorial to fix that issue. I should have updated it ages ago. Please download the file again. Reply
MK
Wed, 11th January 2012
Fixed Version

$(document).ready(function () {

$(' #accordion li').children('ul,p').hide();

$('#accordion li').click(function () {
$(this).children('ul,p').slideUp('normal');

$('#accordion li > a').each(function () {
if ($(this).attr('rel')!='') {
$(this).removeClass($(this).attr('rel') + 'Over');
}
});

if($(this).children('ul,p').is(':hidden') == true) {

$(this).children('ul,p').slideDown('normal');
$(this).children('a').addClass($(this).children('li a').attr('rel') + 'Over');

return false;
}

});

});
Reply
Tyler
Sun, 15th April 2012
Bad UX here, can you make it so the when one opens the others close, but when you click on an open one, it will close without reopening and without causing the whole page to reload? (FFv11 Mac) Reply
Tyler
Wed, 25th April 2012
I fixed the UX to be more usable. This works the same as intended, with the addition of when you click on an open one, it closes. :)

$('#accordion a.item').click(function (e) {
//remove all the "Over" class, so that the arrow reset to default
$('#accordion a.item').not(this).each(function () {
if ($(this).attr('rel')!='') {
$(this).removeClass($(this).attr('rel') + 'Over');
}
$(this).siblings('ul').slideUp("slow");
});

//showhide the selected submenu
$(this).siblings('ul').slideToggle("slow");

//addremove Over class, so that the arrow pointing downup
$(this).toggleClass($(this).attr('rel') + 'Over');
e.preventDefault();
}); Reply
Art
Thu, 28th March 2013
Thanks for code, it works Reply
Christian
Mon, 30th January 2012
Hello There, nice Script !

I use it with mouseover:

$(document).ready(function () {

$('#accordion a.item').mouseover(function () {

//slideup or hide all the Submenu
$('#accordion li').children('ul').slideUp('slow');

//remove all the "Over" class, so that the arrow reset to default
$('#accordion a.item').each(function () {
if ($(this).attr('rel')!='') {
$(this).removeClass($(this).attr('rel') + 'Over');
}
});

//show the selected submenu
$(this).siblings('ul').slideDown('slow');

//add "Over" class, so that the arrow pointing down
$(this).children('a').addClass($(this).children('li a').attr('rel') + 'Over');

return false;

});


});

Can anybody tell me how i can slideUp all when i go outside with the mouse from the #accordion ? Reply
Shannon
Thu, 1st March 2012
Hi there,

Just wondering if it's possible to keep the menu open while I click through the sub menu links.

Currently what happens when I click a sub menu link is it takes me to the page, but on that new page the menu is closed and I have to reopen it.

Thanks Reply
Christine
Mon, 11th June 2012
Was there a solution found for this? I'm also interested in having the menu sub menu open when on a sub menu page. Reply
Oscar Blanco
Tue, 13th March 2012
Hello, and thank you for sharing this useful accordion script.

I'm not a programmer so I'm having a hard time trying to figure out how to make the menu item that is displayed at a time, maintain the "on" look you get from the :hover function.

Meaning, that if you click on it, for instance in the example you have here, the arrow will stay down, on click. Then go back to it's initial state when you click on another menu item.

I've seen the "Over" function on the js, but not the "active" or anything like that.

I hope I made myself clear. Reply
Oscar Blanco
Thu, 22nd March 2012
To clarify further what I'm looking for:

It's ok that the different list items stay opened when clicking on another one. But I would like to at least have the list items that are "opened" to keep their "hover" state. So they look as if they're "turned on" or "active". Reply
juliet
Sun, 15th April 2012
Hi have you found any solution for this? Reply
Kevin Liew Admin
Sun, 22nd April 2012
hey guys, sorry for the late response. I have fixed the issue. Please re-download. Reply
dolores
Fri, 3rd August 2012
hi - great menu thanks for sharing it..

i was wondering how i might make it so that not only do the main menu items have their open state when you are on that particular page, but also when you are on any of the submenu pages... i'd like the main menu item to stay "on" and the submenu items to stay expanded as long as i'm in that section - either on the main menu or any of it's sub-pages... how would i do this...

i would also like to have "on" states for my submenu items...

Reply
edo
Wed, 4th April 2012
Thank you very much for the code, had long been suffering with another menu in javascript, I am new in this and I have two problems, first when loading the page the menu appears unfolded, only when you clik on any menu item starts working, any solution, I'll be doing something wrong? and the other problem is that I need that when you open the new page the link on the menu that it opens in the same state it was when you clik on link Reply
Amit
Thu, 12th April 2012
I hjave used..this code from accordian tutorial and made it dynamic and verified.. that structure .. is totally same. But i m facing problem to call click() method by clicking on main menu ..
Please help me out Reply
Yuva
Wed, 30th January 2013
Hi,
Can you share the sample code that is dynamically populated. Are you using the Struts2/Tiles for this.
Yuva Reply
jessy
Tue, 5th June 2012
Hi, Thanks for this great Tut. But i have small issue in the script when i tried to open it in IE 8, I am using the onclick function script, after the accordion open i see the equal number <div> tag showing at the bottom of the page to the same number tabs in accordion li. Will be much helpful, If you reply. Thanks. Reply
Maciej
Fri, 20th July 2012
How to get index of active part ( index of clicked ul ) ?? Reply
Stephanie
Tue, 23rd April 2013
Hello,

How do you re-collapse an item? I would like to be able to open and close it. Currently you click on the one that is open and it pops up then back down. Thanks! Reply

Leave a Comment

Please keep in mind that comments are moderated and rel="nofollow" is in use. You can use [code][/code] if you want to write codes. Don't spam us :) Thanks!

Advertisement