Overview
Animating an accordion’s height to auto is the canonical CSS frustration — you cannot directly transition height between zero and an unknown value. The grid-template-rows: 0fr → 1fr trick sidesteps the problem: the outer wrapper is a grid track, and grid resolves the row size dynamically. Animating from 0fr to 1fr lets the panel breathe to its natural height with no JS measurement.
When to use it
Reach for the grid-rows accordion on FAQ sections, sidebar filter groups, checkout summaries, settings panels — anywhere a row of content needs to open and close without layout jank. Skip it for content that contains nested accordions of unknown depth (the nested transitions stack oddly) and for content with position: sticky children inside (sticky breaks across grid track changes).
How it works
The outer wrapper sets display: grid; grid-template-rows: 0fr (closed) or 1fr (open). Its only child is an inner wrapper with overflow: hidden; min-height: 0 — without the min-height: 0 the grid track refuses to shrink below the content’s intrinsic size. The actual content lives inside that inner wrapper. Toggling a class flips the grid-rows value, which is a transitionable length per the CSS Grid Level 2 spec, so the height interpolates smoothly. No JS measurement, no scrollHeight reads, no cleanup on collapse.
Production gotchas
Forgetting the min-height: 0 on the inner wrapper is the canonical bug — the grid track stays at the content’s intrinsic height and never collapses to zero, so closing the accordion does nothing. The animation can fight content with its own height animations (nested accordions, expanding images); resolve by giving the outer wrapper a longer transition than the children, or by suppressing nested transitions during the parent transition. Safari needs contain: layout on the inner wrapper to avoid a small flicker at the end of the transition on retina displays.
Accessibility
Use a real <button aria-expanded> for the toggle (or the native <details> + <summary> if styling permits) so screen-reader users hear the expanded/collapsed state. Set aria-controls on the trigger pointing to the panel ID. Under prefers-reduced-motion: reduce drop the transition so the panel snaps open and closed without the height tween — the disclosure pattern still works without motion.
References
Implementation depth
Use this as a disclosure layout primitive, not as a generic height tween. The grid-template-rows 0fr to 1fr trick works because the browser can resolve the intrinsic content height inside a fractional grid track without measuring in JavaScript.
The practical failure mode is nested content that keeps its own overflow visible. Keep the inner wrapper overflow hidden, keep focusable children reachable only when the panel is open, and verify that reduced motion still leaves the expanded state readable.