Foundations
Motion
7 duration tokens and 3 easing curves. Motion here explains a change: something opened, something loaded. It’s functional by default, and the components drop their animation under prefers-reduced-motion.
Demo
Press Play to run a bar over each duration. With reduced motion on, the bars jump to the end instead.
cubic-bezier(0.4, 0, 0.2, 1)cubic-bezier(0.4, 0, 1, 1)cubic-bezier(0, 0, 0.2, 1)
Tokens
| Token | Value | Used by |
|---|---|---|
--duration-skeleton | 400ms | Skeleton |
--duration-spin | 700ms | Spinner |
--duration-interaction | 200ms | Alert, Card, Dialog, Drawer and 18 more |
--duration-transition | 400ms | Alert, Dialog, Drawer, Toast |
--duration-entrance | 600ms | — |
--duration-reveal | 400ms | — |
--duration-reveal-delay | 300ms | — |
| Token | Value |
|---|---|
--easing-default | cubic-bezier(0.4, 0, 0.2, 1) |
--easing-in | cubic-bezier(0.4, 0, 1, 1) |
--easing-out | cubic-bezier(0, 0, 0.2, 1) |
Usage
.panel {
transition: opacity var(--duration-transition) var(--easing-default);
}
.panel[data-state='open'] {
animation: panel-in var(--duration-entrance) var(--easing-out);
}
@media (prefers-reduced-motion: reduce) {
.panel[data-state='open'] {
animation: none;
}
}Do and don’t
Do
- Use the duration that matches the job: interaction for hover, entrance for a dialog opening.
- Ease out for things arriving and ease in for things leaving.
- Give every animation a reduced-motion rule.
Don’t
- Write
transition: 200ms. The linter rejects hardcoded motion in component CSS. - Animate for decoration. If nothing changed, nothing should move.
- Make people wait on an animation before they can act.