Grid Accordion with jQuery

Published
March 22, 2010
by
Chris Coyier

Accordions are a UI pattern where you click on a title (in a vertical stack of titles) and a panel of content reveals itself below. Typically, all other open panels close when the new one opens. They are a clever and engaging mechanism for packing a lot of information in a small space.

Basic accordion from jQuery UI

One way to look at an accordion is like a collapsed single column of a table. I was recently building a page for a client site, where the information that they provided really made sense to present as a table. But it was too much information to view all at once. I thought it would have been overwhelming visually. I also thought that it was most likely that people visiting this page would know what they needed right away, so having them click once to get it seemed pretty reasonable. So, a table of accordions!

Another consideration in this table I was building is that there was enough columns that each individual column (should they have been equal width in the space available) wasn't very wide, maybe 150px. Some of these cells contained several paragraphs of text. A cell 150px wide with several paragraphs of text would awkwardly tall. Hence, the Grid Accordion is born!

The Grid Accordion works with the same theory as most other accordions. Only one cell is open at a time. The big thing is that the column of the current open cell expands to a reasonable reading width.

You can view and download the example at the end of this article. I'll go through some of the important bits next.

HTML: Classic use of the definition list

Accordions are perfect semantic examples of definition lists. A quick review of those:

<dl>
<dt>Title</dt>
<dd>Information about that title here</dd>
<dt>Another Title</dt>
<dd>Information about that other title here</dd>
</dl>

Our grid accordion will be made up of divs floated into a horizontal row. Each div contains the title for the column and an image, as well most importantly the definition list itself. Sample of one of those divs:

CSS: trying to stay accessible

Most of the CSS is just simple setup and not really worth covering here (full CSS file here).

One aspect that is worth covering those is accessibility. We need to "hide" all the information panels of the table by default. One of the ways we could do that is to set the dd elements to display: none; in the CSS. This is a seriously accessibility problems though, as many screen readers will obey that CSS and completely remove that information.

Instead, we can "hide" the cells by just kicking them outside the browser window.

dd { position: absolute; top: -9999px; left: -9999px; }

This is a classic technique. In fact, it's pretty common to see those exact CSS properties and values with a utility class name like this:

We have another concern though. We're going to be using some jQuery animations to slideUp and slideDown the info cells. So we can't have them kicked off the page for typical viewers. We'll move the cells back when the JavaScript first runs and then have the JavaScript hide them.

The thing about the slideDown jQuery function is that it works best when it already knows what height the element originally was before it was closed or hidden, so it can smoothly animate itself back to that original height. If we used display: none; in the CSS, this function would have no idea how tall those cells are supposed to be. Kicking them off the page instead means that the original height will be calculated, keeping that animation as smooth as it can be. We just need to make sure that the cell is set to its "full" width so the height is calculated at the width the cell will be when it's visible.

dd { width: 299px; position: absolute; left: -9999px; top: -9999px; }

So at this point we have an accessible page of information, in that screen readers should be able to get all they need, and regular users have a smoothly operating system. However one thing that isn't fully addressed is simply having JavaScript turned off. In that scenario, the information cells are still hidden by CSS. Personally, I'm far more concerned about accessibility than I am about people who browse around with JavaScript turned off and a torch to bear. However if you are, feel free to either 1) Put in a <noscript> message or 2) remove the CSS hiding and just let there be a bit of a flash of content before the JavaScript hides the cells.

CSS: Fun with CSS3

The CSS3 pseudo class selector :nth-of-type is particularly useful with definition lists. Because the dt and dd elements alternate, and actually can be repeated or in any order, :nth-child would be a non-maintainable way to go. Let's color the cells of the table using :nth-of-type

For the rabble-rabble-IE-compatibility crowd, go ahead and add extra class names to the cells and do your coloring with those hooks.

One of the bits flair we are going to add is highlighting the current column. The class name of "curCol" will be applied and removed as needed via JavaScript. The current column will have a shadow around it, which of course is the perfect use for box-shadow:

While I was playing with this, I originally tried using some transforms to scale up the size of the current column. Ultimately I didn't like the look (one pixel lines look awful when scaled). I liked the shadows much better, but I found that the right edge of the shadow was being cut off the the next column. It was because that next column sat slightly above the current one in terms of vertical stacking order. Hence, the curCol class having the z-index and relative positioning, to make sure it sits on top of the others.

Randomly, I also discovered that the transform property also solved the problem. As in, setting -moz-transform: scale(1); (which scales something to 100%, or basically, does nothing to unscaled elements) also worked by making the shadow visible. In other words: using transforms on elements affects their vertical stacking order. I'm just not sure how it all works exactly quite yet.

jQuery JavaScript

Again I won't cover every line of this (you can see the full file here). Here is the logical structure though:

When a <dt> is clicked...

If it's the currently active cell, do nothing

Otherwise...

Close all open cells

Shrink old title

Enlarge new title

Open new cell

Mark the current column

Make sure current column is expanded and others are shrunk

Couple of interesting things...

I would have normally used the .live() function to handle the clicks on the dt elements. But the newfangled hip way to handle this in jQuery is using .delegate()

$("#page-wrap").delegate("dt", "click", function() {
// do stuff
}

Where live would have to watch the entire document for clicks, delegate limits that watching to only the page-wrap, which is more efficient.

I showed this to Doug Neiner, and he also suggested that clicking on the photos in each column would only open the column. Then if clicked again, they would actually go to the artist's website (where the href of each image links to). The trick here was to prevent the default action (going to the link) when clicking on an image if it's not the current column. Instead, divert the click to the first title in that column (which will open it). We can use delegate for this again:

Demo and Download

Until I figure out some good licensing system... just a reminder than any downloadable example like this on this site you can use to do whatever you want with. Preferably, use it in big corporate projects and make boat loads of cash. Or, show it to your friends and tell them you did it so they will think you are awesome.

“Preferably, use it in big corporate projects and make boat loads of cash. Or, show it to your friends and tell them you did it so they will think you are awesome.”

In all your seriousness, that’s hilarious. This script is incredible though, you always bring something new to the table, I’m sure these types of accordians will sprout up everywhere. Oh and nice CSS3 shadow you have on the highlighted section in the grid accordian.

Quite handy I think, but if you wanna print the content on Safari Mac 4.0.4 well… you’re doomed (just like the doctor)! Be sure to make everything appear in some kind of content so your clients don’t come asking why blank pages are coming out of the printer. Firefox 3.6 Mac seems to deal with this appropriately thought.

wow… too impressive. Many useful techniques on this article, now I understand why many of my attemps to slideDown things went totally wrong (I was hidding the elements in the CSS). I certainly learned a lot jQuery useful functions today :D (I didn’t even know some of them existed)

So cool… I saw this when you twittered about it last week. I’m going to play with it and see if I can tweak it to have a hover state on the “cells” to indicated that they’re clickable and maybe have the inactive columns become grayed out so that the focused column shows up even more prominently.

This looks awesome and very useful. I’m already seeing some great uses for this on my company’s website.

The concern I have is that without javascript the info is not visible. I know a very small percentage browses without javascript, and those people should be used to things looking pretty screwed up around the web. It’s just tough when you’re doing a company site, because you sort of have to cater to the lowest common denominator in terms of visitors.

This is possibly the coolest demo I’ve ever seen on css-tricks; however it does seem to crunch in IE8. It almost seems like IE is /trying/ to animate but it just can’t handle all the processing that goes into play.

But I can’t blame Chris for IE crapping out, and like I said, its way cool. Definitely worth fiddling with for a real client website!

Sorry, I have a very silly question here – have been trying to use it with WordPress and can’t seem to get rid of the ‘is not a function’ message despite trying variations of jQuery(document).ready(function($){. Any help would be much appreciated!

I covered accessibility in the article a bit. The content is accessible for screen readers. It is broken for CSS-On JavaScript-Off people though. If you wanted to fixed that, you’d just remove the position absolute kick-off-the-page stuff in the CSS, as well as the hard coded width. It would look pretty awkward for javascript off people, and javascript on people would see an awkward flash of content before it gets hidden. If you are cool with those things, go for it.

Very cool, I’ve been looking around for something like this for a while. The height and width changing accordion has been really tricky for me. I still haven’t found a way to make it work as a toggle. This comes very close though.

Mr. Chris thanks for this wonderful tutorial, i’m an ardent reader of your blog all the way from Nigeria, pls i want to make a special request, i beg you in the name of God, can you make a screencast of this tutorial pls, because i really need it. Thanks once again and remain bless.

The first thing I tried was to navigate with the arrow keys. I reckon that’d be the next step.
And +1 on the making it work with CSS on JavaScript off comment earlier, I wouldn’t want content to only be accessible with js on.
I’m not all critical though, I really like the concept!

The only issue I have found is that it seems to have killed the scrollbar functionality when added within a site (and infact when I have just tested the demo). Not sure whether this was intended, but for the life of me I can’t work out how to get this functionality back.

Most of my attempts have been focused around “clear: both”, but I might be totally on the wrong track. Any tips?

This is really really cool. I was searching for such a css-/jquery-based accordeon for a while and these existing solutions didn’t fit to me.
Thanks for sharing, Chris! I will use it in my actual project of a shop with several product groups to explain what they are selling.

First off I just want to tank you on this great tutorial and Idea! From the first day I read it I have not been able to get it out of my head. So I am playing with it today.

2nd are there any examples of “Michał Czernow” solution for IE? Still have not wrapped my head around that fix yet. Do I remove the CSS3 and just use old CSS?

3rd When I add extra tabs and include more info in each tab that is more than a screen can hold, I do not get a scroll bar or the ability to go to the bottom of the page. My footer drops but the tabs expanded content stops at the browser’s windows size. Any ideas on how I can fix that? I would prefer to scroll the whole web page and not add scroll bar over flows for the expanded tabs. Also on smaller screens the browser does not give off the side scroll bars also. So content to the right of the screen is cut off.

I have one issue. If I add a thumbnail, and float the image left or right with very little text, the dt element below isn’t spaced properly. The thumbnail ends up floating over the the other elements when it’s dt is the active element.

This comment thread is closed. If you have important information to share, you can always contact me.

Treehouse is where you go to learn HTML, CSS, and how to build iOS apps. It's a complete education in modern web and app technology, designed to get you ready for a hot new job or to kickstart your own business.

The Lodge is a member login only area with access to video training on how to build websites from scratch using the best modern tools.

What now? I have some ideas for you.

Go explore CodePen!

As a front end designer and developer, you should have an account on CodePen so you can save your snippets, present your ideas, and engage with other front end folk. I'd encourage you to go PRO as well, to unlock the full power of CodePen.

Get the newsletter!

You should sign up for the CSS-Tricks newsletter. It's a clean copy of all the blog posts each week, combined together, right to your inbox. If email isn't your thing, there is an RSS feed, iTunes, and lots of other ways to subscribe.

Listen to ShopTalk!

Subscribe to The Lodge!

The Lodge is a members-only, ad-free video learning area here on CSS-Tricks. Just like the free screencasts, but organized into four large complete series. Membership is also the #1 best way to support CSS-Tricks.

We can do the real footer now.

Site Links

Colophon

CSS-Tricks* is created, written by, and maintained by Chris Coyier. It is built on WordPress, hosted by Media Temple, and the assets are served by MaxCDN. The fonts are Source Sans and Source Code Pro. It is made possible by viewers like you who subscribe to The Lodge and through advertising for products and services I like.