Accordion accessibility: use buttons + aria-expanded (not clickable divs)

Short, practical note — with a BEFORE/AFTER micro-demo.

Accordions are a common pattern for settings panels, FAQs, and “advanced options”. The most common accessibility failure is implementing the header as a styled <div> that only reacts to mouse clicks.

Why it matters

Recommended pattern (minimal)

Use a real <button> for each accordion header, and update aria-expanded as it opens/closes. Connect the header to its panel with aria-controls.

<h3>
  <button type="button"
          aria-expanded="false"
          aria-controls="panel-1"
          id="acc-1">
    Graphics
  </button>
</h3>

<div id="panel-1"
     role="region"
     aria-labelledby="acc-1"
     hidden>
  <p>Colorblind mode: On</p>
</div>

Optional (but common): support ArrowUp/ArrowDown/Home/End to move focus between header buttons.

Common pitfalls

Related demos: toggle buttons · tooltips · modal focus