How to build a CSS-only accordion

Temani Afif

Written by Web Developer

March 25, 2023
How to build a CSS-only accordion

In this article, we will create an accordion using CSS. Another common component that we create using minimal code. Most of the tricks rely on <input> hacks but we will do something different here.

Overview of the CSS accordion

The above figure illustrates what we are going to build together.

The HTML markup


For this component, the important part will be the HTML. We are going to use the <details> element that already comes with what we want. Our code will look like below:

<div class="accordion">
 <details>
   <summary>Sesame snaps</summary>
   <div> ... </div>
 </details>
 <details>
   <summary>Chocolate bar</summary>
   <div>...</div>
 </details>
 <details>
   <summary>Donut gummies</summary>
   <div>...</div>
 </details>
</div>

If you run the code and click on the titles you can expand/collapse the content

We are almost done! We already have the functionality of an accordion using a native HTML element.

The <details> HTML element creates a disclosure widget in which information is visible only when the widget is toggled into an "open" state. A summary or label must be provided using the <summary> element. ref

Now, all we need to do is to style it.

25%

đź’¸ EXTRA 25% OFF ALL VERPEX MANAGED HOSTING PLANS FOR WORDPRESS

with the discount code

SERVERS-SALE

SAVE NOW

Styling the accordion

The <details> element comes with two interesting features that we are going to use to style our accordion.

First, we have the ::marker element which is the small triangle next to the title. Each browser will define a default style to the ::marker that changes when we expand/collapse the element.

Then, we have the open attribute. The latter is automatically added to the element when this one is opened.

overview of the open attribute

We can also explicitly define that attribute if we want the element opened by default.

The open attribute is also useful to target the expanded <details> and apply a specific style to it.

Let’s start with some basic CSS:

details {
  margin: 5px;
  font-size: 18px;
}
details > * {
  padding: .75rem;
}
details > div {
  background: #ddd;
  border-radius: 0 0 5px 5px;
}
summary {
  border-radius: 5px;
  font-size: 20px;
  font-family: sans-serif;
  font-weight: bold;
  color: #fff;
  background: #0B486B;
  cursor: pointer;
}
details[open] summary {
  border-radius: 5px 5px 0 0;
}

Nothing complex so far. A few color and font changes for a good-looking accordion:

Notice the use of

details[open] summary {
  border-radius: 5px 5px 0 0;
}

This allows me to define a different border-radius for the <summary> element when the <details> is opened.

Now let’s update the ::marker. To do this, we have two methods

The first one is to override the content like the below:

summary::marker {
  content: "+";
}
summary[open]::marker {
  content: "-";
}

This method is the easiest one but it’s limited. We can change the arrow with any character we want (even an emoji) but we cannot style it like we want due to some restrictions related to the ::marker element.

Only certain CSS properties can be used in a rule with ::marker as a selector: ref

To overcome this limitation we can rely on the second method. We start by making the content of ::marker empty

summary::marker {
  content: "";
}

Then we rely on pseudo-elements to create our own indicator.

details summary::before {
  content:"";
  /* styles when the element is closed */
}
details[open] summary::before {
  /* styles when the element is opened */
}

Now, we can control the CSS as we want. Below is a basic example where I am creating a “plus” and “minus” symbol using gradients (I used the same technique in a previous article)

In addition to the style, I am also changing the position of the indicator to make it on the right. We can also apply some subtle animations to make it look better

I can hear you asking “How to add an animation when open/close the accordion?”. The answer is we cannot but things may change in the future.

Unfortunately, at this time, there's no built-in way to animate the transition between open and closed. ref

We can find some workaround to simulate an animation but for the sake of simplicity, I won’t detail them in this article.

Adding a bit of JavaScript

Now that we have our accordion we can add an optional JavaScript code in case we want to keep only one section opened at a time. There is no relation between the <details> elements and you have probably noticed that we can have all of them open at the same time. If you don’t want such behavior you can add a small JavaScript code:

let details = document.querySelectorAll('.accordion details')

details.forEach(function (d, index) {
  d.onclick = () => {
    details.forEach(function(c, i) {
      index === i ?'':c.removeAttribute('open')
    });
  };
});

We loop through all the details elements and we add an onClick event to each one. Inside the onClick even we perform another loop. For each details element, if it’s different from the clicked one, we remove its open attribute.

Conclusion

The article ends here! We have transformed a simple code into a functional accordion. We didn’t clutter our code with a complex logic. We simply used the native <details> element with a bit of JavaScript at the end. The only drawback is the lack of transition when we open/close each element.

Frequently Asked Questions

Should I build my website with PHP?

Is Joomla Suitable for E-commerce Websites?

How do I make my website HTTPS?

How does adapting websites for mobile users contribute to successful e-commerce website localization?

Discount

Enter Discount Code MOVEME During The SIGN UP Process To Get 90% Off Your First Month

with the discount code

MOVEME

Use Code Now
Jivo Live Chat