Animate <details> with ::details-content and interpolate-size
Animating details open and close without measuring height
<details> has always snapped open and closed. Animating it meant reading scrollHeight in JS, setting a max-height, transitioning, and unsetting on close. ::details-content plus interpolate-size animates the real height natively.
const details = document.querySelectorAll('details');details.forEach((d) => { const content = d.querySelector('.content'); d.addEventListener('toggle', () => { if (d.open) { const h = content.scrollHeight; content.style.height = '0px'; requestAnimationFrame(() => { content.style.height = h + 'px'; }); } else { content.style.height = content.scrollHeight + 'px'; requestAnimationFrame(() => { content.style.height = '0px'; }); } });}); :root { interpolate-size: allow-keywords;}details::details-content { height: 0; overflow: clip; transition: height .3s ease, content-visibility .3s ease allow-discrete;}details[open]::details-content { height: auto;}/* native details, animated open and close */ details content Browser Support
Since 2025 this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.
Works in all modern browsers. May need a fallback for older browsers.
Real height, animated
interpolate-size: allow-keywords turns height: auto into something the browser can interpolate. No more fake max-height ladders or hidden measuring divs.
Native semantics intact
<details> still toggles, screen readers still announce, keyboard still works. The animation is layered on top, not replacing native behavior.
Targets the content directly
::details-content wraps everything inside <details> except the summary. Style it like any element: padding, transitions, transforms.
How it works
Two pieces have to line up. First, interpolate-size: allow-keywords on the root tells the browser to interpolate between fixed values and intrinsic keywords like auto. Without it, height: auto is still a hard switch.
Second, ::details-content selects everything inside <details> except the <summary>. Set height: 0 in the closed state and height: auto in the open state, then transition between them. The allow-discrete keyword on the content-visibility transition keeps the content visible during the closing animation.
The same trick works for any container that needs to grow or shrink to fit its contents. Wrap the toggle in <details> and you get native keyboard handling, ARIA roles, and animated open and close, all from the platform.