HTML Formatterhtmlformatteronline.com

Accordion and FAQ

Built on details and summary — open, close and keyboard support with no JavaScript.

cssaccordionfaqdetailsdisclosure
<div class="faq">

  <details name="faq" open>
    <summary>Does linen shrink?</summary>
    <div class="answer">
      <p>A little on the first wash, which is why good linen is pre-washed before it is cut.
      Ours loses about two percent and then stays put.</p>
    </div>
  </details>

  <details name="faq">
    <summary>Can I tumble dry it?</summary>
    <div class="answer">
      <p>You can, on low. Line drying keeps the fibres softer for longer, and linen dries faster
      than almost anything else, so it is rarely worth the machine.</p>
    </div>
  </details>

  <details name="faq">
    <summary>Why does it crease so much?</summary>
    <div class="answer">
      <p>Because the fibre is stiff and hollow, which is the same reason it is cool to wear.
      Creasing is a property of the cloth, not a defect in it.</p>
    </div>
  </details>

  <details name="faq">
    <summary>How should I store it?</summary>
    <div class="answer">
      <p>Folded and loose, somewhere dry. Long spells on a wire hanger stretch the shoulders,
      and plastic covers trap moisture.</p>
    </div>
  </details>

</div>

How it works

<details> and <summary> are a disclosure widget built into HTML. They open, close, respond to Enter and Space, and announce their expanded state — with no script at all. Most accordion libraries exist to reimplement this badly.

display: flex on summary removes the marker. The default triangle disappears as soon as you change the display type, which is the cleanest way to get rid of it. list-style: none covers Firefox and the ::-webkit-details-marker rule covers older Safari.

The name attribute makes it exclusive. Giving several <details> elements the same name turns them into a radio group: opening one closes the others. This is a recent addition and it removes the last reason people reached for JavaScript here. Drop the attribute and they open independently.

The chevron is two borders on a rotated pseudo-element. No icon file, no font, and it inherits nothing you have to keep in sync — the rotation flips with details[open].

::details-content is what finally allows animation. Height could never be transitioned to auto, which is why every accordion library measured the content and animated a pixel value. The new pseudo-element plus allow-discrete handles it in CSS. Browsers without support open instantly, which is the behaviour everyone had until recently.

An inset focus ring. outline-offset: -2px draws the ring inside the summary, so it is not clipped by the container's overflow: hidden.

Accessibility notes

<summary> is exposed as a button with an expanded state, so a screen reader announces "Does linen shrink? button, collapsed" and updates when it opens. That is the whole contract, and you get it for nothing.

Do not add role="button" or aria-expanded by hand. Both are already implied, and adding them can conflict with the native semantics.

Keep the summary text short and meaningful on its own. Screen reader users often pull up a list of all the buttons on a page, and "Read more" four times in a row tells them nothing.

Making it yours

For an FAQ page, add FAQPage structured data that matches the visible questions. The markup must describe what is actually on the page — marking up an FAQ the visitor cannot see is a structured data violation.

To have the first item open on load, put open on it as shown. With name set, only one item may carry open in the initial HTML.

Content inside a closed <details> is still in the DOM, so browser find-in-page can reach it and modern browsers will open the section automatically when it matches.

Related templates

Check your version

Once you have edited this, the HTML validator will catch any tag you left unclosed, and the formatter will tidy the indentation. Both run in your browser.