Create a Simple, Intelligent Accordion Effect Using Prototype and Scriptaculous
Tutorial Details
- Technology: JavaScript, CSS
- Difficulty: Beginner - Intermediate
- Completion Time: 1-2 hours
We’ve all seen the “accordion” type effect used on many Web 2.0 sites; however, many accordion scripts are heavy, make poor use of the libraries they are based on, and don’t handle things like ensuring that the accordion maintains a consistent height. In this tutorial, we will use the Prototype and Scriptaculous libraries to create a lightweight, intelligent accordion.
Demo and Source Code
Step 1 - The Goal
Our objective is to create a lightweight accordion script based on the Prototype and Scriptaculous javascript libraries.
The accordion should:
- Allow an unlimited number of accordion panes
- Be completely styled by CSS
- Be Unobtrusive—users without javascript turned on should see all of your accordion content
- Be Light Weight—With relatively few lines of code; use event delegation to limit memory consumption.
- Support any kind of content within the accordion
- Ensure that when the content of each accordion pane changes, the height of the accordion remains constant to avoid
the annoying “page bouncing” effect
This is a relatively advanced tutorial that assumes the reader has a reasonable knowledge of Javascript, CSS, HTML, Object-Oriented
programming, and a basic understanding of the Prototype and Scriptaculous libraries. However, complete source code is
available for you to study and the code is very simple to read and learn from if you are not familiar with the specific
libraries used.
Before we begin, you can see a working demonstration of the accordion in action.

Step 2 - Begin with Basic Markup
To begin, we will create some simple HTML markup for our accordion:
<div id="test-accordion" class="accordion">
<div class="accordion-toggle">Toggle 1</div>
<div class="accordion-content">Content 1</div>
<div class="accordion-toggle">Toggle 2</div>
<div class="accordion-content">Content 2</div>
<div class="accordion-toggle">Toggle 3</div>
<div class="accordion-content">Content 3</div>
<div class="accordion-toggle">Toggle 4</div>
<div class="accordion-content">Content 4</div>
</div>
Step 3 - Add Some Style
Next, we need to add some style around our accordion to make it look like an accordion. To begin with, we’ll do a first pass of basic styling and then add more when it’s all working. There are also some additional
styles that need to be included to ensure that the accordion will display correctly as it is animating.
div#test-accordion{
margin: 10px;
border: 1px solid #aaa;}
div.accordion {
position: relative; /* required for bounding--works around a "peculiarity" in Prototype */
}
div.accordion-toggle{
position: relative; /* required for effect */
z-index: 10; /* required for effect */
background: #eee; /* required for effect--can be anything except "transparent" */
cursor: pointer;
}
div.accordion-toggle-active{
background: #fff;
}
div.accordion-content{
overflow: hidden; /* required for effect */
background: #aaa;
}
See the basic accordion with a simple stylesheet.
Step 4 - Create the Javascript Accordion Class
Prototype provides a wonderful framework for building classes in Javascript and we’ll use that functionality to build
our accordion class. This class will contain all the properties and methods of an accordion: the currently displayed
pane, the contents of the accordion, methods to expand and contract panes, and event handler methods to define what happens
when users take an action such as clicking. For now, we’ll set up the basic structure of the class as well as all the
properties and methods we’ll need:
var Accordion = Class.create({
initialize: function(){
this.accordion = null; /* Stores a pointer to the the accordion element */
this.contents = null; /* Array of pointers to the headings and content panes of the accordion */
this.options = null; /* Allows user to define the names of the css classes */
this.maxHeight = 0; /* Stores the height of the tallest content pane */
this.current = null; /* Stores a pointer to the currently expanded content pane */
this.toExpand = null; /* Stores a pointer to the content pane to expand when a user clicks */
this.isAnimating = false; /* Keeps track of whether or not animation is currently running */
},
checkMaxHeight: function(){}, /* Determines the height of the tallest content pane */
initialHide: function(){}, /* Hides the panes which are not displayed by default */
attachInitialMaxHeight: function(){}, /* Ensures that the height of the first content pane matches the tallest */
expand: function(el){}, /* Tells the animation function which elements to animate */
animate: function(){}, /* Performs the actual animation of the accordion effect */
handleClick: function(e){} /* Determine where a user has clicked and act based on that click */
});
These are the basic methods and properties that we will need when building our accordion. Each of the next steps will
take you through building each method until we have a working accordion. If at any point during the tutorial you need
a quick refresher on what each method or property is for, you may use this heavily commented code as a reference.
Step 5 - Initialize: Get Things Started
Prototype classes have a special method called initalize() which is a constructor; this means it acts when the user
creates a new instance object of that class. For any accordion, we need to know 2 things before we begin:
- The id of the accordion element.
- The default starting position of the accordion (if anything other than the first position)
So, we will need to allow our constructor to accept those two parameters. Additionally, our constructor must:
- Retrieve and store the accordion and its contents as pointers to those elements
- Set the user defined options
- Set the current expanded element
- Determine the maximum height we will use as the height for all of our content panes and apply it
- Hide the content panes which are not shown by default
- Add an event listener to the accordion to watch user clicks.
Here is the code for our initialize() method:
initialize: function(id, defaultExpandedCount) {
if(!$(id)) throw("Attempted to initalize accordion with id: "+ id + " which was not found.");
this.accordion = $(id);
this.options = {
toggleClass: "accordion-toggle",
toggleActive: "accordion-toggle-active",
contentClass: "accordion-content"
}
this.contents = this.accordion.select('div.'+this.options.contentClass);
this.isAnimating = false;
this.maxHeight = 0;
this.current = defaultExpandedCount ? this.contents[defaultExpandedCount-1] : this.contents[0];
this.toExpand = null;
this.checkMaxHeight();
this.initialHide();
this.attachInitialMaxHeight();
var clickHandler = this.clickHandler.bindAsEventListener(this);
this.accordion.observe('click', clickHandler);
}
As you can see, we’ve set all of our properties to reasonable default values and called 3 methods to help get things set
up. Finally, we’ve attached the event handler to the accordion. Let’s create those three methods and the event handler.
Step 6 - Checking the Tallest Element
One of the requirements for our accordion is that it must scale so that even when the tallest content pane is expanded,
the overall accordion height will remain constant. To accomplish this goal, we will iterate through the content panes
determining which one is the tallest and set the maxHeight property accordingly:
checkMaxHeight: function() {
for(var i=0; i<this.contents.length; i++) {
if(this.contents[i].getHeight() > this.maxHeight) {
this.maxHeight = this.contents[i].getHeight();
}
}
}
Step 7 - Hiding the Rest
Our accordion should only display the content pane specified as the current pane; all others should be hidden
by default. Additionally, we need to set these content pane’s height attribute to 0; this prevents the content pane from
briefly appearing fully expanded before properly animating.
initialHide: function(){
for(var i=0; i<this.contents.length; i++){
if(this.contents[i] != this.current) {
this.contents[i].hide();
this.contents[i].setStyle({height: 0});
}
}
}
Step 8 - Show the Default Content Pane
Now that we’ve hidden all but the default content pane, we need to make sure the default content pane displays correctly;
it’s heading should have the “active” style applied to it and it’s height should match the maxHeight property:
attachInitialMaxHeight: function() {
this.current.previous('div.'+this.options.toggleClass).addClassName(this.options.toggleActive);
if(this.current.getHeight() != this.maxHeight) this.current.setStyle({height: this.maxHeight+"px"});
}
Step 9 - Create the Event Handler
If you come from a traditional event handling background where we attach the event handler to each area we want clickable,
it may seem confusing that we are only attaching the handler to one element. We are using event
delegation. For those of you unfamiliar with the subject, I have written a brief
overview of event delegation which
will introduce you to the concept and why it is so important. That said, we need an intelligent event handler:
clickHandler: function(e) {
var el = e.element();
if(el.hasClassName(this.options.toggleClass) && !this.isAnimating) {
this.expand(el);
}
}
There are two parts to this function. First, we determine what was clicked. Then, we check to make sure that it was a
heading that was clicked and that no animation is currently running. If this is the case, we call the expand() method
to start the process of the accordion. The variable we pass to the expand() method is the heading on which the user clicked.
Step 10 - Start the Process
Now we can start the process of doing the accordion effect. We know the expand() method must take a parameter for the
element which was clicked. Using that parameter, the expand method determines which content pane to expand, and if it
is not already expanded, calls the animate() method to “do its magic!”
expand: function(el) {
this.toExpand = el.next('div.'+this.options.contentClass);
if(this.current != this.toExpand){
this.toExpand.show();
this.animate();
}
},
Step 11 - Doing the “Dirty Work”
At this point, all of the pieces are in place; we know which content pane is currently displayed, we know which heading
the user has clicked, and we know which content pane the user has requested to be shown. Now, we must create the accordion
animation. For this, we will create an animate() method that will use the Scriptaculous Effect.Parallel class to render
the two animations together; and the Effect.Scale class to change the size of each content pane. The animate method will
perform these steps:
- Create an array that will be used to store our Effect.Scale objects
- Collect the parameters to pass to the Effect.Scale constructor for the content pane that will be shown and create
the object - Add that object to our array
- Collect the parameters to pass to the Effect.Scale constructor for the content pane that will be hidden and create
the object - Add that object to our array
- Create the Effect.Parallel object that will run our Effect.Scale objects is sync.
- Tell our Accordion object that we are animating
- Run the animations
- Clean up any styles left behind
- Tell our Accordion object that we are finished animating
animate: function() {
var effects = new Array();
var options = {
sync: true,
scaleFrom: 0,
scaleContent: false,
transition: Effect.Transitions.sinoidal,
scaleMode: {
originalHeight: this.maxHeight,
originalWidth: this.accordion.getWidth()
},
scaleX: false,
scaleY: true
};
effects.push(new Effect.Scale(this.toExpand, 100, options));
options = {
sync: true,
scaleContent: false,
transition: Effect.Transitions.sinoidal,
scaleX: false,
scaleY: true
};
effects.push(new Effect.Scale(this.current, 0, options));
new Effect.Parallel(effects, {
duration: 0.5,
fps: 35,
queue: {
position: 'end',
scope: 'accordion'
},
beforeStart: function() {
this.isAnimating = true;
this.current.previous('div.'+this.options.toggleClass).removeClassName(this.options.toggleActive);
this.toExpand.previous('div.'+this.options.toggleClass).addClassName(this.options.toggleActive);
}.bind(this),
afterFinish: function() {
this.current.hide();
this.toExpand.setStyle({ height: this.maxHeight+"px" });
this.current = this.toExpand;
this.isAnimating = false;
}.bind(this)
});
}
For a complete explanation of the option parameters we are passing to both the Effect.Scale and Effect.Parallel objects,
please see the Scriptaculous documentation.
The important aspects of the method are the beforeStart and afterFinish methods on our Effect.Parallel. The beforeStart
method tells the accordion that it is currently animating. This will prevent the event handler from attempting to start
any further changes so long as the animation is in progress. It also makes sure that the heading which was clicked is
given the “active” class name. The afterFinish method completely hides the content pane which had been previously displayed
(after it has disappeared due to the animation). It also ensures that the final height of the newly displayed content
pane is correct. Now that the swap is complete, it tells our accordion that the currently expanded content pane is the
one we have newly expanded and that the animation is complete.
Step 12 - Adding Some More Style
At this point we have a decent looking accordion, which you can see in action here. But with a little CSS we can make it all look much more spectactular. So first we create a quick Photoshop mockup so we have a rough idea of how it should all look. With that in mind, we’re going to need three images:
- A ‘logo’ image –

- A couple of nice background images –
and 
And here’s the revised CSS code:
body {
padding: 130px 50px 50px 50px;
background: #252422 url(../img/logo.gif) no-repeat;
background-position: 60px 40px;
font-family: "Lucida Grande", "Lucida Sans Unicode", Arial, Sans-serif;
font-size: 11px;
line-height: 18px;
}
div#test-accordion{
border: 1px solid #343230;
background-color: #21201f;
padding: 10px;
}
div.accordion {
position: relative; /* required for bounding */http://net.tutsplus.com/wp-admin/users.php
width: 800px;
}
div.accordion-toggle{
position: relative; /* required for effect */
z-index: 10; /* required for effect */
background: #3f3c38 url(../img/off.jpg) repeat-x;
background-position: bottom;
color: #fff;
cursor: pointer;
margin-bottom: 1px;
padding: 9px 14px 6px 14px;
border-top: 1px solid #5d5852;
}
div.accordion-toggle:hover, div.accordion-toggle-active{
background-image: url(../img/on.jpg);
background-color: #6d493a;
border-top: 1px solid #a06b55;
}
div.accordion-content{
overflow: hidden; /* required for effect */
background: #302e2c;
color: #c4bab1;
border-bottom: 1px solid #000;
}
div.accordion-content p{
margin: 9px 24px 6px 24px;
}
As you can see here we’ve:
- Added some background styles around the page and the accordion class
- Given the accordion-toggle div a regular background color
- Set the accordion-toggle:hover and the active states to use the same reddish background
Step 13 - See It in Action

You can see the working demonstration here. You can also add your own CSS and images
to tailor the look to your site.
Download: accordion.js & accordion.css










jQuery Lightbox Evolution only $12.00
Events Calendar Pro - Wordpr ... only $30.00 
Hello, very nice tutorial !
I’m looking for the synthax to expand or collapse all elements, what should I do ?
Hi,
Excellent tutorial ! Now please tell me how I can make the accordion working for both onclick and onmouseover.
Thanks in advance.
Dear Brian Crescimanno , thank you for this fancy script , put i like to ask , when we load the page ” the Main ” tap was Open , how can load the HTML page and all taps closed !
@Cesc
Read my post earlier. I have a solution to the maxHeight problem, probably not the only way to do it, but it works.
@Geoff
Has anyone had a problem with your height script working in IE6 and IE7. I got it to work great in Firefox and Safari but in IE the accordion windows don’t open.
Thanks for the tutorial..
How can we allow the divs to take the size of the content rather than the max height?
Any idea?
Neat tutorial, nice and simple to follow and the final outcome looks very professional. Thanks guys.
Thank you, awesome accordion! I am using it in a huge project and it’s helping out very nicely! However, I was wondering if it is possible to make it so that the content area is as long as the content for that specific content area. Instead of having it be as long as the longest content area. I noticed that each content area is as long in height as the longest content area.
Hope that makes sense, but I am fighting for space and it would be awesome if there is a way to make it so that each content section is only as long as the content itself and not the same across each content area.
Thanks again!!!
Is anyone having issues with this displaying correctly in IE7? For me it’s working but when the page loads the entire accordion is open.
Any help would be appreciated.
Awesome tutorial. It inspired me to make my portfolio website an accordian style. But in my site, I’d like to use 300 x 100 px pictures instead of the words “Main” and “Why use us” etc. But when you hover over the pictures and click, it doesnt initiate the animation.
As you can see I just inserted a picture in the spot i wanted it:
Is there any way to make an image like this clickable to trigger the animation? Any help would be GREATLY appreciated! Thanks!
Loving this script, thanks muchos! One question – I recently had problems with pagination – I have a list with 9 items. Each item has nested items, which is where the accordion comes in handy. However, my max number to be displayed on one page is 8, leaving just one item displayed on page 2.
This throws an error “this.current is not defined” and when I went back through the code, I found that the very last lines where the accordion is initialized read :
=====
document.observe(“dom:loaded”, function(){
accordion = new Accordion(“test-accordion”, 2);
})
=====
I changed the 2 to a 1 and everything’s fine. Just wondering though, why it’s set to default to 2?
Great tutorial Brian ..
I ahve beens truggling with another ‘well-known’ accordion script without any success… I implemented yours in a couple of minutes +++ I learned a lot about why it’s designed like that… as a non-JS specialist, I took the time to discover the code … thanks again !! I’ll definitly markup your site and subscribe to your publications via RSS
In case anyone still is interested, it appears I changed it to auto scale instead of using maxHeight.
In fact, this can be achieved by changing 2 lines.
In the animate function, there is one line reading “originalHeight: this.maxHeight,” (should be about line #81)
This needs to be changed to “originalHeight: this.toExpand.scrollHeight,”
The other line is like 4 lines above the end of the class and originaly reads ” this.toExpand.setStyle({ height: this.maxHeight+”px” });”
Change this to ” this.toExpand.setStyle({ height: “auto” });”
This works perfectly for me. Hope it does for you
You are a life saver… fantastic… what is needed for this tutorial is this bit of stuff that you had added… this tut is good but its made better by your mod… Thanks a lot.
To add to that the other bit of code that needs to be removed is
this.current.previous(‘div.’+this.options.toggleClass).addClassName(this.options.toggleActive);
if(this.current.getHeight() != this.maxHeight) this.current.setStyle({height: this.maxHeight+”px”});
line 53 and 54… if you dont the intial height will be the same as the longest content pane.
Oh many many Thanks for this ‘hack’
You sir, are a legend! This was driving me insane
)
Wonderful tutorial. Very professional.
Could anyone please show me how to achieve the effect same as BySildeMenu http://www.byscripts.info/scripts/javascript-dynamic-accordion-menu Example 10 that has fixed height and if content is more than the fixed height can hold, scroll bar will be shown on right hand side of accordion?
Thanks.
Hey, I like
Is there any way to have all elements default on page load as collapsed?
Also, for it to be possible to click the element that is open and active to collapse? Basically to open and close all the elements so one doesn’t have to remain open at all times.
I’m using this for a work project so if a quick response is possible, that would be awesome!
Thanks!
ps. all work files are on my localhost and it is for a very large application so I can’t provide any working links or examples of what I have so far.
How do i do auto height for the content panes?. I am not an expert on js if someone can give me an idea of how to do it, would be great. I dont want the one size for all slider.
Awsome
HELP!
I made a webpage with the great accordion effect!
Now i want a specific part of the menu to expand (fold out) for a current page.
Anybody has a clue? :
http://www.burobengel.nl/fs/index.html
Thanksss….
How to add Nested Vertical accordion? Is is any method I can add in the same tutorial files?
If anyone still experience the “jerkyness” with the accordion open up the demo html page and link yourself to the css code page to find the new and improved css code. copy that css code and replace the css code you got from the source file, which happens to be jerky. Worked like a charm for me. Link coming up shortly from my site i created with this effect
Great tutorial!
Is there a way to hide everything by default and only open an item by clicking it?
i have the same question,
I found simplist solution is to do the following
if accordion got 4 links then make the default open one 5
e.g. document.observe(“dom:loaded”, function(){
accordion = new Accordion(“contact-accordion”, 5);
})
Hi,
I like the coding you made, can we made the content panel within the panel meaning a sub panel, and can i use xml to use it.
I am sending u a site which is in “Flash” and very simple in preview.
I want to make the similar site, but in html format can we do it like that.
Sorry i forgot to show u the site it’s
http://alextrochut.com/
great tutorial, thanks, great help
It is working great. Css styling is excellent too. 200 out of 100!
very beautiful plugin
Can we use this script as intrusive?
I can’t use like this, because i want to use the script after loading it by ajax.updater(), so non intrusive methods are not valid to me :’(
Have you a solution?
PS: Thanks for this great script.
I have used your tutorial to build an accordion menu. I used the simpler one without all the fancy css.
I have a problem with it though.
My portfolio is a one page deal with a central div tag into which i load content using AJAX (when i click on links). That content is separate html pages with text and images.
I put that accordion menu into one of those separate html pages, and when i load that page into the div tag, the accordion menu doesn’t work.
I have tested another situation where i put the accordion menu in the parent page, and it works fine. Also when the separate page is tested by itself the accordion works as well.
All javascripts are in the parent page, and the paths are correct.
Somehow javascript can’t execute. Any suggestions?
Nice accordion, but there is a missing option to make it vertical.
Bonjour,
Tres bien mais..manque de détails..(les noms des fichiers où integrer les scripts)..les nuls sont encore une fois oubliez.
En tous cas, beau travail, bravo!
tutorial good. i very like it. thank for this tutorial
Can somebody tell me how i can make multilevel accordion with this plugin?
Hey Everyone,
I’m using the accordion but have come across an issue in Firefox (Mac and PC). I’m pulling in content that’s using the accordion in an iFrame from site A to site B. This works fine in all browsers (IE, Chrome, Safari), but in FF the content areas do not expand for some reason unless I reload the iFrame, then it works fine. Somehow the height is set to 0 the first time the iFrame is loaded (checked this with Firebug).
However, once I reload the iFrame the accordion works fine. Really puzzled here about what could be causing this … any help would be greatly appreciated!
Hi Has anyone found a way to:
a) Make all the panes collapsed by default
b) Make it so that when you click on the pane header, it both does the expand and collapsing for the content rather than clicking on another pane. Just so that you do not have to view any content at all if desired?
If anyone could help it would be much appreciated. I am working on a website at my job, and it is important that I can get this working. {:\
How to Trigger slider click manually?
Very smooth Animation of Accordion Effect Using Prototype and Scriptaculous
Thanks for Download…
http://www.raghibsuleman.com/jquery-common-accordion-horizontal-vertical