← Sketches
Native HTML

<details> / <summary>

Built into the browser. Zero CSS required. No animation by default, but you get keyboard support, correct open attribute state, and the right semantics for free.

What makes this approach special?

The browser handles open/closed state entirely. The open attribute is toggled automatically, giving you a reliable CSS hook. The downside: discrete open/close with no transition — content just appears.

Can I style the disclosure marker?

Yes — use summary::marker or summary::-webkit-details-markerto swap or hide it. Replace it with your own icon via ::before and rotate on [open].

CSS Only

Checkbox hack

A hidden <input type="checkbox"> holds the open/closed state. A <label> acts as the trigger. CSS sibling selectors (:checked ~ .content) show or hide the panel. No JS, but no animation either.

The checkbox's :checked pseudo-class is the state machine. Because the label and content are siblings of the checkbox in the DOM, you can target them with:checked ~ label and :checked ~ .body. The browser tracks checked state natively.

Accessibility is the main concern — screen readers announce this as a checkbox, not a disclosure widget. You can patch it with role="button" andaria-expanded on the label, but at that point a small JS sprinkle is cleaner.

CSS Only · Animated

grid-template-rows

Wrapping the content in a single-column grid and transitioninggrid-template-rows between 0fr and 1fr produces a smooth height animation with no JS and no fixed pixel values. The inner element needs min-height: 0 to collapse fully.

CSS can't interpolate between height: 0 and height: autobecause "auto" isn't a numeric value. But grid-template-rows: 0fr → 1fris numeric — the browser knows exactly how to tween it. The content's natural height becomes the 1fr track and collapses to zero cleanly.

All modern browsers since 2023. The transition on grid-template-rowslanded in Chrome 107, Safari 16, and Firefox 110. It's safe to use without a fallback for most production sites today.

CSS Only · Newest

interpolate-size

The interpolate-size: allow-keywords property — set on :root — unlocks transitions to and from intrinsic sizing keywords like auto,min-content, and max-content. You can finally writeheight: 0 → height: auto directly.

Likely yes. interpolate-size alongside the calc-size()function is the spec's intended solution. The mental model is the simplest of any technique here: animate height like you'd animate any other property. Currently Chrome 129+ and Edge 129+; Firefox and Safari support is in progress.

Setting interpolate-size: allow-keywords on :root is a broad opt-in — it changes how all keyword-to-length interpolations work in the document. Scope it carefully if you're mixing with other animation libraries that do their own height tweening.

Javascript

Javascript

For comparison: a button sets aria-expanded, the panel toggles a class, and CSS animates the transition using the grid-template-rows trick. More verbose, but fully accessible and easy to extend (e.g. closing siblings, deep-linking to an open panel).