Motion
Behavior, not brand. Fade poppers. Scale centered dialogs. Translate sheets.
Motion is a system concern. Looks do not retune it. Durations live on primitives:
--duration-fast is 120ms (control marks), --duration-base is 200ms (everything
else). Easing is --ease-out (cubic-bezier(0.16, 1, 0.3, 1)).
Utilities: animate-fade-in / out, animate-pop-in / out, animate-check-in.
Pop animates scale, not transform, so it does not stack on a centering
translate. Always pair with motion-reduce:animate-none.
animate-fade-inanimate-pop-inanimate-check-inOverlay rules
Never animate transform on a popper or a centered overlay. Radix poppers
already position with transform. Dialogs center with -translate-x-1/2 -translate-y-1/2. Fighting those makes the panel jump.
| Overlay | Motion | Why |
|---|---|---|
| Dropdown, select, tooltip, popover | Fade only | Popper transform stays intact |
| Dialog, alert-dialog | Fade overlay + pop content | Pop uses scale |
| Sheet | Fade overlay + slide | Slide uses translate tokens |
| Accordion, collapsible | Height keyframes | Token accordion / collapsible |
| Checkbox mark | animate-check-in | Fast duration |
className={cn(
"data-[state=open]:animate-fade-in data-[state=closed]:animate-fade-out",
"motion-reduce:animate-none",
)}Sheets use animate-slide-in-right (and left / top / bottom). Accordion and
collapsible use animate-accordion-* / animate-collapsible-*. Do not reach
for tw-animate-css. Keyframes are dry-* in bindings.css.
See Tokens for the token ladder. Dialog, sheet, and menu docs show the overlay pattern in situ.