Transition Panel
Direction-aware animated swap between named views with auto-animated height
Preview
Sign in
Enter your email to receive a code.
Installation
Usage
Examples
Vertical Axis
Slide views along the Y axis instead of X. Useful for stepped flows where movement should feel like turning a page rather than navigating left/right. The container's height also animates as the active view's content size changes.
Overview
High-level snapshot of the workspace. Click next to drill in.
API Reference
TransitionPanel is a pure-CSS compound component — there is no underlying Base UI primitive. Views register themselves through context, so TransitionPanelView does not need to be a direct child: wrappers, fragments, conditional rendering, and Suspense boundaries are all supported.
The entrance animation uses @starting-style and transition-behavior: allow-discrete. Older browsers degrade to an instant swap with no slide — no broken state, just no motion. The component also respects prefers-reduced-motion.
Props
TransitionPanel
Outer container. Renders a <div> and accepts any native div prop (id, role, aria-label, ref, data-*, style, etc.). Composes a consumer ref with the internal ref used for height measurement.
Data attributes
Set on the root element so consumers can style based on transition state.
CSS custom properties
Set on the root and inherited by view wrappers. Override via the style prop or a CSS rule.
TransitionPanelView
A single view registered with the parent panel. Renders a <div> and accepts any native div prop (className, style, id, aria-label, aria-labelledby, ref, data-*, etc.) in addition to those documented below — spread props land on the view wrapper. The consumer ref is composed with the internal ref used for registration with the parent panel. Visibility, slide offset, and inert state are driven by the parent's activeKey. Inactive views stay mounted (their internal state survives swaps) but are marked inert and aria-hidden so focus and assistive tech skip them.
Data attributes
Notes
- Composability. Views can be wrapped in HOCs, fragments, error boundaries, Suspense boundaries, or rendered via
.map()and conditional logic — registration routes through context, not React children. - Direction inference. Direction is computed by comparing the new and previous
activeKeyagainst the registered view order, so back-navigation slides the opposite way automatically. Re-deriving from DOM position on each registration means a view that unmounts and remounts (e.g.{isPro && <TransitionPanelView ...>}) keeps its source-order slot. - Focus management. Focus moves in a
useLayoutEffect, before the browser paints, to minimize the gap between the outgoing view becominginertand the incoming view receiving focus. - Height animation. Animates the real
heightproperty (viaResizeObserver) rather thantransform: scale, so descendant layout doesn't warp. Acceptable for typical panel use cases; if you need compositor-only height animation for a high-frequency surface, fork to a Motion / FLIP implementation.