Home / Snippets / UI Components /

CSS accordion

details / summary styled — open/close behavior is built-in.

What is CSS Anchor Positioning? +
Anchor Positioning lets you tether a floating element (tooltip, popover) to another element using CSS alone — no Popper.js required.
Is :has() widely supported? +
Yes — :has() is supported in Chrome 105+, Safari 15.4+, and Firefox 121+. It covers the vast majority of users in 2026.
What is animation-timeline? +
animation-timeline: scroll() ties a CSS animation to scroll position so you can build scroll-driven effects without JavaScript. The bar fill in the scroll progress snippet uses this.
Widely supported
uino-js

Quick implementation

/* HTML: <details class="acc-item"><summary>Title <span class="acc-icon">+</span></summary><div class="acc-content">...</div></details> */

.acc-item {
  border: 1px solid oklch(0 0 0 / 0.07);
  border-radius: 0.75rem;
  overflow: hidden;
  background: white;
}
.acc-item summary {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.85rem 1.1rem;
  cursor: pointer; font-weight: 600;
  list-style: none; /* hide default triangle */
}
.acc-item summary::-webkit-details-marker { display: none; }

/* Rotate icon on open */
.acc-icon {
  font-size: 0.8rem;
  transition: transform 0.25s;
}
.acc-item[open] .acc-icon { transform: rotate(45deg); }

/* Style summary when open */
.acc-item[open] summary { color: oklch(0.52 0.22 265); }

.acc-content {
  padding: 0 1.1rem 0.85rem;
  border-top: 1px solid oklch(0 0 0 / 0.07);
  font-size: 0.875rem; color: oklch(0.48 0.025 260);
}

/* Smooth height transition (new — requires interpolate-size) */
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }
}

Prompt this to your LLM

Includes animated height transition and React variant.

You are a senior frontend engineer building accessible UI components.

Goal: A styled FAQ accordion using <details>/<summary> — no JavaScript for open/close.

Technical constraints:
- Use <details> and <summary> for native open/close. Style with .acc-item[open] for open state.
- Hide the default marker: summary { list-style: none } + summary::-webkit-details-marker { display: none }.
- Show a +/× icon (or SVG chevron) via a <span> inside summary, rotated on [open] with transform: rotate(45deg).
- Each panel's content sits in a <div class="acc-content"> below the summary.
- Use border-radius on the item, a subtle border, and a border-top on the content area.

Animated height transition (bonus):
- Use interpolate-size: allow-keywords in :root and transition: height on details to get smooth open/close in browsers that support it. Provide a non-animated fallback for others.

Framework variant (pick one):
A) Vanilla HTML + CSS — a 3-item FAQ.
B) React — an Accordion component that accepts items as an array of { question, answer } props. The [open] attribute is managed by the browser; no React state needed.

Edge cases:
- Multiple open at once (default behavior with details).
- To restrict to one open at a time, note that a <details name="group"> attribute (new, limited support) or a small JS pattern would be needed.

Return full HTML + CSS.

Why this matters in 2026

Accordions are everywhere — FAQ sections, settings panels, mobile nav. Using <details>/<summary> gives you open/close for free, including keyboard (Enter/Space) and screen reader support. CSS handles the visual state with [open]. No useState, no event listeners, no bundle cost.

In 2026, the interpolate-size: allow-keywords property (shipping in Chrome 129+) finally enables smooth height transitions on details elements using transition: height — something that previously required JavaScript or max-height hacks.

The logic

The [open] attribute is toggled by the browser when the user clicks the summary. .acc-item[open] .acc-icon rotates the plus icon. .acc-item[open] summary colors the trigger. The content panel shows because it's a normal child of the <details> element — no display toggling needed.

The details[name] attribute (new, partial support) allows multiple <details> to share a group name so only one is open at a time — like a proper "exclusive accordion." Use it as a progressive enhancement.

Accessibility & performance

The <details> element has full ARIA semantics built in. Screen readers announce "expanded" and "collapsed". Keyboard users can tab to the summary and toggle with Enter or Space. Don't add role="button" to the summary — it already is one. Zero JavaScript means the accordion works during page load before scripts execute.