Smooth Accordion Expand/Collapse

Animate accordion panels from collapsed to expanded heights — the height-transition problem that has plagued web devs for a decade — using View Transitions snapshots.

UI Patterns

Detailed Explanation

The Auto-Height Animation Problem

Animating from height: 0 to height: auto has been impossible in pure CSS forever. The workarounds — measuring with JavaScript, animating max-height, or using grid-template-rows: 0fr → 1fr — all have caveats. The View Transitions API sidesteps the problem entirely by snapshotting both states.

function toggle(panelId) {
  document.startViewTransition(() => {
    document.getElementById(panelId).hidden = !document.getElementById(panelId).hidden;
  });
}
.accordion-panel {
  view-transition-name: var(--panel-name);
}
::view-transition-old(.accordion-panel) {
  animation: 200ms ease-out both shrink;
}
::view-transition-new(.accordion-panel) {
  animation: 250ms ease-out both grow;
}
@keyframes shrink {
  to { opacity: 0; transform: scaleY(0.5); }
}
@keyframes grow {
  from { opacity: 0; transform: scaleY(0.5); }
}

The siblings shift smoothly

The killer feature: when the panel expands, all the sibling panels below it also animate to their new positions through the root cross-fade group. You did not write any code to make that happen — the API captures the entire viewport and animates every visible element.

Differentiating panels with view-transition-name

If two accordions are open simultaneously and you want each to animate independently, give each a unique view-transition-name like panel-faq-1, panel-faq-2. Without unique names, all panels share the root group and animate as one.

Pairing with the <details> element

The native HTML <details> element and View Transitions work together beautifully:

details.addEventListener('toggle', (e) => {
  document.startViewTransition(() => { /* nothing! the toggle already happened */ });
});

Wait — that does not work because toggle fires after the DOM change. Use click on the <summary> and call preventDefault() to control the timing.

Use Case

FAQ sections, settings panels, hierarchical navigation menus, file tree viewers, and any disclosure widget where you want smooth height + sibling-shift animation without measuring DOM heights manually.

Try ItView Transitions API Generator

Open full tool