useExitTransition
Keeps an element mounted through its CSS exit transition. This is the design
system's replacement for JS animation-library "presence" wrappers: the exit
is pure CSS (a motion preset's [data-state="closing"] state), and the hook
only decides when the DOM node can go away.
When open flips to false, the element re-renders with
data-state="closing" — the exit transition starts — and unmounts on the
first matching transitionend, backed by two guards: a timeout fallback at
the computed transition time plus slack (transitionend is lossy), and a
synchronous unmount when the computed duration is zero (reduced-motion
kill-switches, test environments, or no transition at all).
When to use
| ✅ Use when… | 🚫 Avoid when… |
|---|---|
|
|
Signature
const { mounted, state, ref } = useExitTransition(
open: boolean,
opt?: { property?: string },
);mounted— render the element whiletrue; flips tofalseafter the exit finishes.state— mirror asdata-state={state}on the animated element ('open' | 'closing').ref— attach to the element whose transition drives the unmount.opt.property— only atransitionendfor this CSS property completes the exit (useful when several properties transition and one is the authoritative "done" signal, e.g.grid-template-rowson a collapsing wrapper).
Example
function Toast({ open, children }) {
const { mounted, state, ref } = useExitTransition(open);
if (!mounted) return null;
return (
<Flex ref={ref} motion="slide-up" data-state={state}>
{children}
</Flex>
);
}Accessibility
Under prefers-reduced-motion: reduce the motion vars zero the transition
durations, so exits complete almost immediately — the hook needs no special
handling. When a closing element carries a live region (role="status"),
set aria-hidden="true" during the closing phase so screen readers do not
announce content that is on its way out.
See also
- The
motionprop (motion presets) — the CSS side of this contract. - Motion concept page — tokens, reduced motion and the enter/exit model.