21

The eternal problem: you can't transition height: auto, so every accordion prompt gives me either a JS height-measuring hack or a max-height guess that's either clipped or has a laggy delay when content is short.

The modern trick is animating grid-template-rows from 0fr to 1fr on a wrapper, which transitions cleanly to the content's natural height with zero JS and no magic numbers. I wrapped it in <details>/<summary> for free semantics and keyboard support, then added reduced-motion.

Dropping the prompt. My open question: any gotchas with nested accordions using this technique? I saw a jump when the inner one animates.

THE PROMPT
Build a CSS-only accordion using native `<details>`/`<summary>` with a smooth open/close animation and no JavaScript.
- Animate the reveal by wrapping the panel content in a grid wrapper and transitioning `grid-template-rows` from `0fr` (closed) to `1fr` (open). This gives true auto-height animation with NO fixed heights, NO `max-height` guesses, NO JS measurement.
- The inner content element needs `overflow: hidden; min-height: 0` so it collapses correctly.
- Transition: `grid-template-rows 240ms cubic-bezier(0.4, 0, 0.2, 1)`. Also fade content `opacity` 0->1 slightly delayed.
- Style the `<summary>`: remove the default marker, add a custom chevron that rotates 180deg on open via `[open]`, cursor pointer, and a `:focus-visible` outline (never remove it).
- Do not break keyboard operability that `<details>` gives for free.
- `@media (prefers-reduced-motion: reduce)`: instant open/close, no row or opacity transition.
Output the full HTML + CSS. Note which element carries the overflow:hidden and why min-height:0 is required.
0fr -> 1fr finally killed my max-height hack across the whole codebase. No more clipped content on long panels.designbynight 2 months ago
add a comment

2 Answers

19

This is the right technique and using <details> for it is chef's kiss. For your nested-accordion jump: the inner grid animates at the same time the outer is still resolving its own 1fr, so the outer sees a moving target. Fix is to give the inner wrapper will-change: grid-template-rows and, more importantly, ensure each level has its own min-height: 0 on the content, not just the outer one. The jump is almost always a missing min-height: 0 on an intermediate element.

THE PROMPT
Add for nested cases: every grid wrapper at every nesting level needs `overflow: hidden; min-height: 0` on its content child; do not rely on inheritance.
8

Small taste note: 240ms is fine for a short panel but feels sludgy for a tall one because perceived speed scales with distance. I ask the model to keep duration constant but ease harder (steeper curve) so long panels still feel snappy. Constant duration + distance-aware easing reads better than scaling the time.

Your Answer