Pure CSS toggle accordion

CSS is brilliant. When written properly you can do so much with it. I believe that you should always try to build crucial UI elements with CSS rather than JavaScript. It always feels slightly more responsive, and now with transitions you can make things look amazing with just one line. So I thought I would try my hand at creating an accordion. We have all made one at some point, usually utilizing a massive JavaScript library such as MooTools or jQuery alongside a bloated accordion script. So my version uses no JavaScript whatsoever.

I admit, because of using newer CSS, namely the :checked pseudo selector, you alienate your older IE audience. But that can be fixed by including Selectivizr. So you have your increased performance and ease of use in newer browsers with a working version in IE. The first thing you will need is the HTML.


Now the HTML for this particular accordion is a little more complicated than some. That is because we are utilizing radio buttons to perform the toggle on click action. But do not fear, it only means one extra element that is actually set to display: none.

I have only added two content panes here, but you can add as many as you require. As you can see, we have a simple unordered list with a class applied to it (
). Each list item contains a label, input and div. The label is where you store your title and the div is where you put your content. You can style all of this however you want. Just adapt my CSS that I will show you in a second.

When adding more items you must remember to update the for attribute on the label and the id of the radio input. Otherwise you will click one and six will show. You can also specify a content pane to be open by default by adding checked='checked' to its radio button, just like I have done in the HTML above. Other than that you can just copy and paste to your hearts content.


Now here is the code that makes the accordion work. I have added comments to help you out, but you may still find it a bit confusing. If you do just utilize it in your project via copy and paste first, then keep tweaking it until you know what does what. I believe that it is one of the best ways to understand some confusing code. Style it up, add some transitions. Maybe even adapt it to work horizontally. Just don’t say “bah! that looks too hard, I give up”. Just experiment.

So this CSS first adds some basic styles, so we can actually distinguish between content panes, and then adds the radio button based functionality. This relies heavily on the adjacent sibling selector (+). So in the last selector we are saying: “any div with a class of ‘content’ that is under a checked radio button that is under a label should be displayed”. See, that’s not so bad is it, and that is the most complicated line!

The main question is, does it work? Well yes, yes it does. And here is an example. Here is a fiddle too, just in case you want to play about with the code as well as the accordion itself.

  • Adam Gunderson

    I hate my IE audience!

    • Ha! I think it is more about the browser than the audience itself, but still. It is always good to add more support if it is easy to do. Take the html5shim polyfill for example. One line that is only actually parsed in IE that fixes so much.

      You can do the same with Selectivizr and it should work fine. Just put it in an IE conditional comment for IE9 and below with the shim script.

  • Nice tutorial. 

    Good idea with using the checked pseudo class, I’ve done this before using the :target pseudo class, think I prefer the checked option.

    • Glad you liked it! Some people seem to think using :checked and form elements is a bad idea, but I believe it is perfectly acceptable. An accordion is basically a form containing radio buttons that you can’t submit anyway.

      Would be interesting to use this in a package selection for a service for some kind. So you select beginner, normal or pro, for example, and you have a description as well as great feedback for your selection. Just a thought.

      • Hi Oliver

        I didn’t really think of using this as a form item. I would normally use something like this to display featured information on the page.

        • True, that is the usual use. I just meant using the checked pseudo selector in conjunction with a sign-up form of some kind to display extra information about the users selection.

          Maybe not the best idea to hide things away, but might be useful when working with limited pixels.

          • Yea true might be useful on mobile site. 

            Do you know if it works on mobile devices? That will be a good place for an accordion sign up form.

          •  Yep, I am pretty sure it works perfect. It was introduced in FireFox in version 1.0 and works perfectly on my HTC Desire. I would imagine the WebKit based iOS browsers would work fine too.

            There are some good stats on this page.

  • Tom

    Great work! Bummer it doesn’t work in IE 9 (and possibly previous versions).

    •  True, it is not great in the IE department. But if you add Selectivizr in an IE conditional tag it will work perfectly.

      • avater

        hmm how does that work…having problems opening the menus on ie9…

  • Daivd Huosãr

    One possible accessibility issue you’ll run into is that you cannot ‘tab’ on to the radio buttons as they are hidden (and the label won’t get picked up by tabbing either).

    This seems like a great technique though overall. I would love to know if there is a way around the tabbing issue – as I’m gearing up to integrate this method into my current toolkit.

    I also tried using checkboxes which work in much the same way except with the added function of being able to toggle all items open at the same time.

    • Daivd Huosãr

      ah.. does not work in iOS – on closer inspection. Both safari and chrome.

  • KD

    Love what this can do and it’s perfect for my book excerpt options.  However, it just shows the radial and full content without the accordion effect.  I’m new at this, so I know I’m doing something wrong.  What do I need to do (copy/paste info) in order to have someone review? 

  • Ruben Solvang

    I have unsuccessfully tried to apply a CSS3 transition when the different content is shown / hidden. Do you know if this is possible at all?

    • You can do it, but you need a tiny bit of JavaScript. You could have your JavaScript add a class to an element called hidden or something like that. This will start to fade the element out or do what ever you want it to do. The JavaScript can then listen for the transition end event which it can set display: none; or add another class to completely hide it. I’ve built you a little example of how I would do it. I hope this helps: http://jsfiddle.net/Wolfy87/cSXMZ/

  • Bruce Velocity

    It was great, until I tried using it in IE. Using an ordered list inside the content causes IE (9 specifically, but all the other crappy ones would probably be the same), to use the same number as the UL used for the titles.

  • lupil

    CSS ding dong tralala