You might not need Javascript for that: Accordions

This is the second installment of “You might not need Javascript for that”, a series aimed at showing how CSS can be used to do tasks that are usually done in Javascript. The purpose of the series isn’t to show how CSS is better than Javascript (it isn’t) but to bring to light a few tricks that not everyone may be aware of. Just like most crafts, there are many tools available in web development, and the best tool for the job largely depends on it’s specific situation. The idea behind this series is to show alternative solutions that might be handy in certain instances.

The focus of this post will be Accordions, a component that are likely to be familiar to most developers. Accordions are useful for pages that have lists of content, like “Frequently Asked Questions” pages. A nice feature of accordions is that they allow the user to quickly scan for the specific information that they care about, and then expand the details of that content out by clicking. In this way they serve a function somewhat similar to a menu.

I’ve created a demo accordion below. It’s pretty basic, but it fits the description above and also includes some animations. Bootstrap is being used for the base styling, glyphicons, and grid layout of this example.


Kinda nifty, huh? And no Javascript necessary. So how does it work? I feel like there are three critical components:

  1. The :checked selector – Basically CSS has an easy way to detect whether a checkbox is checked or not.
  2. The ~ (sibling) selector – Another really powerful selector, it lets you change the styling of an element based on it’s siblings.
  3. The ability for a checkbox label to toggle the checkbox on click, even if the label is in a different location and even if the checkbox itself is not visible at all.

You can combine the three ideas above to toggle basically anything on click. First place the checkbox in the same parent container as the elements that you want to toggle (it is important that the checkbox is placed before and not after, as the ~ selector will only look at preceding elements. I feel like CSS should have a selector that does the opposite as well, but right now it doesn’t). Next wrap the element that you want to be clickable (in this example it is the arrow glyphicon) in a label with a “for” reference to the checkbox. Finally apply the checked and sibling selectors to define how the elements display when the checkbox is checked, and set the checkbox itself to display: none.


As usually, it is hard to explain code with words, so please check out the codepen itself.

Another part of this example is the transitioning of the paragraph as the accordion opens as closes. While you don’t necessarily have to do this, I think that it provides a better UX this way. Since you can’t actually transition from height: 0 to height: auto, I transitioned the max-height from 0 to a value that should be higher than the expanded height.


This technique isn’t without it’s limitations. These include the following:

  1. You need to set an id for each item of the accordion. This is certainly doable and even HTML generated by a backend templating language could do this, but it does add some complexity and I’ll admit that it does feel a little wrong to do things this way.
  2. This is kind of a lot of CSS and HTML compared to a Javascript solution. Setting up a click event and toggling a few classes is pretty easy in Javacript and is probably less confusing than this pure CSS approach.
  3. Using Javascript will give you a better ability to transition the height of the accordion paragraphs. The max-height trick used here is actually not very good unless you know the final height of the paragraph – most of the time you won’t and this will vary across screen widths. In the demo codepen you may have noticed that there is a slight delay when you collapse an accordion item – the max-height transition is causing this.


Accordions can be built without Javascript! That being said, I feel that the downsides of this approach outweigh the benefits, and I will likely stick to a solution involving Javascript in most situations.