Platinum Partner
css,frameworks,javascript,web design,jquery,client-side,html & xhtml,ajax & scripting

Playing Accordion With CSS and jQuery

One of the problems web designers face on a daily basis is the limits that are placed on one with regards to the size of your 'canvas'. Bigger screens with higher resolutions has helped a great deal in this regard but the problem definitely has not disappeared. 

However, when you start looking at ways to save screen real estate using JavaScript, the job becomes much easier. In this tutorial we will look at how to show and hide bits of content using a combination of CSS and the awesome jQuery library, and just for kicks, I am going to use version 1.3 of jQuery.

NOTE: Everything here can be done with the 1.2 versions of jQuery as well. 

Let's get started then. First thing is to download the latest version of jQuery. Next I created a simple project containing two folders, one for JavaScript and one for the CSS. Next I created the HTML file:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Playing Accordion With CSS and jQuery</title>
</head>
<body>
</body>
</html>

The scenario we are going to play out here is a basic frequently asked questions page. In general you will have a title, which is the question, and following this, one or more paragraphs providing the answer to the question. The problem is, as the amount of questions increases the user needs to scroll more and more to find the question they need an answer to.

Sure, you could create a table of contents with anchor links to the questions or, the user could simply use the find function of the browser but, for the purpose of this tutorial we are going to imagine our client not wanting a table of contents and, we definitely do not want our users to have to resort to external 'tools' to find answers to their questions.

Right after the opening body tag add three heading tags to the page as follows:

<h2>Question 1</h2>
<h2>Question 2</h2>
<h2>Question 3</h2>

Now after each heading add some paragraphs with some random text, you can grab some jibberish from this very useful site to speed things up. After having added some paragraphs my page now looks as follows:

[img_assist|nid=7411|title=|desc=|link=none|align=none|width=550|height=269]

Our next step is to wrap each of our answers in either a span or a div with each having a class of answer. We also need to give them an id that is the same as the anchor link we used in the heading:

<h2><a href="#answer1">Question 1</a></h2>
<span id="answer1" class="answer">
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</span>

To finish of we enclose the entire FAQ section in a div with an id of #faq.

On the surface nothing have changed but, as mentioned we are now all set to both style our FAQ's as well as add the interactivity we require. Let's start by adding some style. Create a new CSS file called default.css inside your CSS folder and then link it up to your HTML page as follows:

<link rel="stylesheet" href="css/default.css" type="text/css" media="screen">

What we are going to do now is change our font's size and add some icons and styles to our headings.

For the icons I used the Sweetie icon set that you can freely dowload from the sublink.ca website. The two icons I used in this tutorial are:16-square-green-add.png and 16-square-green-remove.png

Once you have copied the two icons to a folder inside your project we can start with the first of our style rules. First I changed the color and size of our headings to fit better with the icons.

h2 
{
background-color:#fff;
color:#94AE6B;
font-size:1.1em;
}

Next we need to make our headings links, to make it more obvious that they are clickable and provides a fallback for when JavaScript is not enabled. Basically the links will act as anchor links and jump to the answer. Add the following to your heading tags:

<h2><a href="#answer1">Question 1</a></h2>

Next give your links some style:

h2 a:link, h2 a:visited
{
color:#94AE6B;
text-decoration:none;
}
h2 a:hover, h2 a:focus
{
color:#CBB052;
}

We are almost ready to add the behaviour layer but before we do, we need to add two more style rules. Currently we have not used the icons. For this we need to create two states for the headings, one for when the content is hidden and one for when the content is shown. Add the following to your CSS file:

h2.maximized
{
background:#fff url('../media/icons/maximize.png') center left no-repeat;
padding-left:20px;
}
h2.minimized
{
background:#fff url('../media/icons/minimize.png') center left no-repeat;
padding-left:20px;
}

Next change your heading tags as follows:

<h2 class="maximized"><a href="#answer1">Question 1</a></h2>

Now when you refresh you page it should look as follows:

[img_assist|nid=7413|title=|desc=|link=none|align=none|width=550|height=189]

Now you may asked, how the heck will we ever see the minimized style? Well, jQuery and our behaviour layer comes to the rescue. Before we can start using jQuery however we need to link the library to our HTML page as follows:

<script src="js/jquery-1.3.min.js" type="application/javascript"></script>

Now that we have the library attached we need to create our own little js file to hold our scripting. Create a new .js file and link it to the HTML page as we did the previous one. Our first task is to hide all of the paragraphs.

When we want to script HTML with JavaScript we are basically manipulating the Document Object Model (DOM) but before we can do that, the browser needs to parse the HTML and build up the DOM. So how do you know when the DOM is ready for you to start manipulating? Let jQuery handle that for you. Inside our .js file add the following:

$(document).ready( {

});

What this jQuery function does is poll the browser to determine when the browser has done it's parsing and the DOM is ready to be manipulated. The important thing to remember here is that it does not wait until the browser has loaded all of the images and other media but will trigger the function inside ready() as soon as the DOM is ready.

Next step is to add our function that will hide all of the paragraphs as soon as jQuery has determined that the DOM is ready. Change the above code as follows:

$(document).ready(function()
{
$('.answer').hide();
});

When you now refresh your page things have changed!

[img_assist|nid=7415|title=|desc=|link=none|align=none|width=128|height=110]

Awesome! So through that one simple line of JavaScript, jQuery has selected all of the elements in the document with a class of answer and applied the CSS display:none; property to it. Now we need to apply the required functions to the headings so that when it is clicked it will show the answer and when clicked again, it will hide the answer.

You might be thinking that this will be a combination of .show() and .hide() functions, right? Wrong! jQuery here again makes things a lot simpler for us. jQuery gives us the .toggle() function that, you guessed it, toggles between the hidden and shown state.

The .toggle() function takes two parameters that will be the functions run on show and hide. Change your script to the following:

$(document).ready(function()
{
$('.answer').hide();

$('#faq h2').toggle(
function() {

},
function() {

}
);
});

This is our skeleton where all the action will happen. To show and hide our answers we are going to add two simple lines in each of the empty function() methods:

$(document).ready(function()
{
$('.answer').hide();

$('#faq h2').toggle(
function() {
$(this).next('.answer').show();
},
function() {
$(this).next('.answer').hide();
}
);
});

Go back to your HTML page, hit refresh and click on any of the three headings. First click will show the answer, next click will hide the answer. But how does it know which answer to show or hide? The magic is the $(this) keyword. $(this) Refers to the current element responding to the event, which in our case is the currently clicked heading.

So how will we see the minimized style rule? For this we are going to use two new methods that jQuery gives us namely .addClass() and .removeClass(). Now there are two ways we can handle this. The first option is:

$(this).removeClass('maximized')
$(this).addClass('minimized');

This will work fine but jQuery gives us another powerfull option that saves us some typing. Change your script to the following:

$(document).ready(function()
{
$('.answer').hide();

$('#faq h2').toggle(
function() {
$(this).next('.answer').show();
$(this).removeClass('maximized').addClass('minimized');
},
function() {
$(this).next('.answer').hide();
$(this).removeClass('minimized').addClass('maximized');
}
);
});

The way we are adding and removing our classes in the above code is what is called method chaining and is just one other way jQuery makes coding simpler. If you now go back to the browser and click on a heading you will see that the icon changes as expected:

[img_assist|nid=7418|title=|desc=|link=none|align=none|width=276|height=217]

That is it! jQuery has many other ways to show and hide content to make your web site or application just that little bit more interactive. I would encourage you to visit the jQuery site, read the documetation and look at the samples. But most importantly, have fun!

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}