Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to make an accordion

Short answer

The details tag opens on a click on summary — without a single line of JavaScript:

<details>
  <summary>How long is delivery?</summary>
  <p>Usually two to four working days.</p>
</details>
<details>
  <summary>Can I return an item?</summary>
  <p>Yes, within 30 days of purchase.</p>
</details>

Only one open

The same name attribute on several details makes them a group: opening one closes the others:

<style>
  .faq { border-bottom: 1px solid gainsboro; padding: 8px 0; }
  .faq summary { cursor: pointer; font-weight: 600; list-style: none; display: flex; justify-content: space-between; }
  .faq summary::after { content: "+"; }
  .faq[open] summary::after { content: "−"; }
</style>
 
<details class="faq" name="faq" open><summary>Shipping</summary><p>Free from $50.</p></details>
<details class="faq" name="faq"><summary>Payment</summary><p>Cards and PayPal.</p></details>
<details class="faq" name="faq"><summary>Returns</summary><p>Within 30 days.</p></details>

list-style: none removes the default triangle, and ::after draws a custom icon that changes on an open section [open].

Smooth opening

details used to open only with a jump. In new browsers smoothness comes from interpolate-size: allow-keywords together with a transition on the ::details-content pseudo-element; elsewhere the section simply opens at once.

Common mistake

People build an accordion from a div with a click handler. Such a block does not open from the keyboard, and a screen reader does not know it expands. details and summary give you all this for free — use them.

Functions used in this recipe

  • <details>, <summary> — A disclosure block without JavaScript: `<summary>` is the visible title, the rest is hidden until clicked.
  • transition — Animates the change of a property from the old value to the new one.
  • ::marker — The bullet or number of a list item.

Thanks for reading!

Donate to the site — we work hard for you.