Motion
Four durations, three easings, wired as Tailwind's defaults, and the mandatory reduced-motion guard.
Last updated
Motion is token-driven like everything else. Every animated component reads the
tokens below and respects prefers-reduced-motion.
Tokens
| Token | Value | Use |
|---|---|---|
--duration-rapid |
100ms | Hover fills, press feedback |
--duration-fast |
150ms | Menus, toggles, tooltips |
--duration-medium |
250ms | Panels, popovers, chevrons |
--duration-slow |
400ms | Dialogs, expanding regions |
--ease-standard |
cubic-bezier(0.2, 0, 0, 1) |
Default: quick start, soft landing |
--ease-accelerate |
cubic-bezier(0.4, 0, 1, 1) |
Leaving the screen |
--ease-decelerate |
cubic-bezier(0, 0, 0.2, 1) |
Entering the screen |
Easings become utilities (ease-standard, ease-accelerate,
ease-decelerate). Durations stay CSS variables: in scoped CSS use
transition: opacity var(--duration-fast) var(--ease-standard); in markup use
duration-[var(--duration-medium)].
Defaults
Tailwind’s default transition duration and easing point at
--duration-fast and --ease-standard, so a bare transition-colors is
on-brand:
Hover me
Show codeHide code
<div class="rounded-md border border-neutral bg-elevation-raised px-4 py-2 text-sm transition-colors hover:bg-primary hover:text-on-primary motion-reduce:transition-none">
Hover me
</div>Reach for an explicit duration only when the default is wrong for the size of the move:
Slower
Show codeHide code
<div class="… transition-colors duration-[var(--duration-medium)] ease-decelerate …">Slower</div>Reduced motion
Every transition and animation carries a guard. In markup, motion-reduce:transition-none.
In scoped CSS:
@media (prefers-reduced-motion: reduce) {
.apogee-thing {
transition: none;
}
}
Looping animations (Spinner, Progress, Marquee, Skeleton) keep their own durations; the scale above is for transitions. Under reduced motion they slow down or stop rather than disappear, so the state they communicate stays visible.
Do / Don’t
- Do use
ease-deceleratefor things that appear andease-acceleratefor things that leave. - Don’t write a literal
150msor acubic-bezier()in a component. - Don’t animate layout properties (
height,top) whentransformor::details-contentcan do it.