For the past eight(8) years Schalk Neethling has been working as a freelance developer under the pseudo of Volume4 and is now the president of Overt Strategy Consulting. During this period he has completed over 300 projects ranging from full web application development to complete branding. As president and lead developer of Overt Strategy Consulting, Schalk Neethling and his team has released a 100% Java standards based content management system called AlliedBridge and business document exchange and review system, called Doc-Central. Schalk Neethling is also actively involved on a daily basis in the open source, web standards and accessibility areas and is a current active member of the Web Standards Group. Schalk is also the co-founder and president of the non-profit The South Web Standards and Accessibility Group, which aims to actively educate and raise awareness of web standards and accessibility to both the developer society as well as business large and small. Schalk also has a long relationship with DZone and is currently zone leader for both the web builder, css.dzone.com, as well as the .NET zone, dotnet.dzone.com, and you can find a lot of his writing there as well as on his blog located at schalkneethling.alliedbridge.com. Schalk is constantly expanding on his knowledge of various aspects of technology and loves to stay in touch with the latest happenings. For Schalk web development and the internet is not just a job, it is a love, a passion and a life style. Schalk has posted 173 posts at DZone. View Full User Profile

Playing Accordion With CSS and jQuery

01.19.2009
| 20382 views |
  • submit to reddit

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:

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:

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!

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:

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!

Published at DZone with permission of its author, Schalk Neethling.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Ton Haarmans replied on Sun, 2010/07/11 - 2:05pm

Hi,

Your tutorial was very helpful. Thanks for that!

Still I have something to ask. I tried it myself a couple of times, but since I am a n00b, it didn't work. I would like it when one level shows, the other levels hide...

I hope you can help!

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.