Speed
Slow motion multiplier
1×
Reduced motion
Show

The exit gap

the brief overreaches here
Eleven components animate in and vanish out, and the brief calls fixing all eleven the highest-leverage change in the audit. Checked against the sources it cites, most of them are already right: an exit earns its place when it aids orientation, and a surface the user has already looked away from does not qualify. What survives is narrower and still worth doing — useLayer cannot express an exit at all, which blocks the four or five surfaces that genuinely want one.Decide here: Which surfaces earn an animated exit, and what enter and exit cost on the ones that do.

Tune the presence budget

These two values drive every pane on this page, and every layer demo in the lab.
enter
230ms
exit
175ms
overlay
410ms
Exit ships shorter than enter, which is beUI’s rule — old content should leave faster than new arrives. Treat it as a default rather than a law. Emil scopes asymmetric timing to system responses versus deliberate actions, and a dialog the user chose to close and is watching may want the full enter duration. Drag them equal and judge it per surface rather than globally.

Which of the eleven actually earn an exit

Orientation is the test, not presence. Three of these are named in the published page as instant-dismissal surfaces — the rest is judgement, so argue with it.
earns one
Dialog, AlertDialog
Dismissal reveals the page underneath, and the user chose it deliberately. The published page names a dialog as its own example of an exit worth animating.
earns one
Lightbox
Full-screen. Without an exit the underlying page reappears with no explanation of where the image went.
earns one
BottomSheet, MobileNav
Spatially anchored to an edge, so the exit has an obvious direction and the entrance already established it.
earns one
CommandPalette
Modal and it covers content — but it is also a power-user surface hit many times a day, so this is the row most likely to flip on frequency grounds.
instant is fine
Tooltipnamed in the docs
The pointer has already left. Highest-frequency surface in the system, so criterion 2 argues against motion here even before orientation does.
instant is fine
HoverCardnamed in the docs
Same shape as Tooltip: dismissal is a side effect of the user moving somewhere else.
instant is fine
DropdownMenu, ContextMenunamed in the docs
The menu has done its job the moment a pick is made, and attention has moved to whatever the pick affected.
instant is fine
Popover
Not named on the page, but the same class. Worth a second look if a popover is ever used as a panel rather than a hint.
instant is fine
Selector, ComplexSelector, MultiSelector, Tokenizer
Dropdown-class. Attention is on the field and the value that just landed in it, not on the list closing.
instant is fine
Typeahead, PowerSearch, MoreMenu, Breadcrumbs overflow
Same. All of these are the user getting somewhere, and the surface closing is not the event.
Four surfaces earn an exit and seven do not, which inverts the brief’s framing: the fix is not eleven components short of a dismissal animation, it is a shared primitive that cannot express one for the four that want it. The work is the same size. The justification, and the rubric gate that follows from it, are not.

What an exit looks like on a surface that may not want one

All four demos below are surfaces the triage puts in the “instant is fine” column, and three are named in the published page. They are still worth looking at — you cannot judge whether a dismissal aids orientation without seeing the alternative — but read them as the question rather than the fix. The card that follows them, Dialog, is the clear case for.

Tooltip

useLayer · highest-frequency surface in the system
The published page names tooltips specifically as a surface that may vanish. Does the exit earn its 175ms here, on something seen hundreds of times a day?
Today — animates in, vanishes out
Tooltip
Proposed — the exit retraces the entry
Tooltip

HoverCard

useLayer · the most visible instance of the gap
A larger surface travelling the same distance. Judge the scale-from value here rather than on Tooltip — 0.96 reads differently at size.
Today — animates in, vanishes out
HoverCard
Proposed — the exit retraces the entry
HoverCard

Popover

useLayer
Click twice quickly. The exit has to retarget rather than restart, or rapid dismissal looks broken.
Today — animates in, vanishes out
Popover
Proposed — the exit retraces the entry
Popover

DropdownMenu

useLayer · submenus too
A menu snapping shut is the case people notice. Does the exit help, or does it just delay the next click?
Today — animates in, vanishes out
DropdownMenu
Proposed — the exit retraces the entry
DropdownMenu

Dialog, AlertDialog, CommandPalette

focus races the exit
Two separate bugs in one surface: the panel has no exit, and the backdrop has no transition at all. Watch the focus ring on the trigger.
Today — no exit, scrim hard-cuts, focus returns immediately
Delete workspace?This cannot be undone.
Proposed — panel and scrim both exit, focus waits
Delete workspace?This cannot be undone.
In the left pane the focus ring lights the instant the dialog closes, while the dialog is still on screen. With a real exit animation that means focus moves — and the page may scroll — mid-animation. The brief lists this as a risk; here it is a thing you can watch, and it has to be settled before the Dialog work starts rather than after.

The technique, running natively in this browser

Is the platform enough, or does the shared primitive need a JS fallback? This card answers it for real — nothing here is simulated.
A native popover transitioning display and overlay with allow-discrete, entering from @starting-style. This is the proposed implementation, not a mock-up of it.
Green across the row means the shared presence primitive can be built on the platform with no JS fallback, which is the question the spike exists to answer.

What one change buys

Every component below is a useLayer consumer, so all of them inherit a dismissal animation from a single definition. That is the leverage — and it is also the risk, because it is one change to the code path that owns dismissal.
TooltipHoverCardPopoverDropdownMenuContextMenuSelectorComplexSelectorPowerSearchTypeaheadMoreMenuBreadcrumbs overflow
layerAnimations — one definition, eleven consumerscss
.layer {
opacity: 0;
transform: scale(0.96) translateY(-4px);
transform-origin: var(--layer-origin);
transition:
opacity var(--duration-exit) var(--ease-exit),
transform var(--duration-exit) var(--ease-exit),
display var(--duration-exit) allow-discrete,
overlay var(--duration-exit) allow-discrete;
}
.layer:popover-open {
opacity: 1;
transform: scale(1) translateY(0);
transition:
opacity var(--duration-enter) var(--ease-entry),
transform var(--duration-enter) var(--ease-entry),
display var(--duration-enter) allow-discrete,
overlay var(--duration-enter) allow-discrete;
}
@starting-style {
.layer:popover-open { opacity: 0; transform: scale(0.96) translateY(-4px); }
}
useLayer — await the exit instead of hiding synchronouslytsx
- setOpen(false); // element gone this frame
+ setClosing(true); // stops accepting input immediately
+ await Promise.all(
+ el.getAnimations().map(a => a.finished),
+ );
+ setOpen(false); // focus return happens here

What this work has to be careful about

Dismissal is load-bearingLayer dismissal has its own invariants test for good reason. Keeping an element alive through its exit doubles the state matrix for focus return, outside-press and escape handling — and every one of those has to be tested against an element that is visible but already closing.
The published page already warns about thisAnimations that block interaction are worse. If a user has to wait for a panel to finish sliding before they can click something inside it, the animation has become an obstacle.” The answer has to be that the surface stops accepting input the moment dismissal starts, not when the animation ends. Write that into the primitive’s contract rather than leaving it to each consumer.
Motion is already fighting the automated gatesTwo fixes landed this month to stop animation interfering with the accessibility audit and the visual-regression capture. More motion means more of this, and there is no documented policy for it. The lab’s reduced-motion switch doubles as the freeze mode a capture needs.