Centrim Design System — a token-first, accessible React component system.
Motion
Motion exists to explain a change, never to decorate one. It is fast, small in distance, and always optional — a person who asks for reduced motion gets none of it.
What is this?
Four duration tokens (instant, fast, normal, slow), three easing curves (standard, emphasized, linear), and a single ds-transition utility that components apply to interactive state changes.
When to use it
- State feedback on hover, press and focus
- Something entering or leaving: menu, dialog, drawer, toast
- Progress and loading indicators that need continuous motion
How to use it
- Use fast for hover and press, normal for surfaces entering or leaving
- Use the standard curve unless a surface needs emphasis on entry
- Animate transform and opacity — not layout, width or height
What to avoid
- Animating anything longer than the slow duration
- Motion that moves content the user is reading
- Custom keyframes when ds-transition already covers the case
Tokens
Durations and easing curves available as --ds-duration-* and --ds-ease-*.
- duration-instant
- duration-fast
- duration-normal
- duration-slow
- ease-standard
- ease-emphasized
- ease-linear
What each duration is for
| Duration | Use for | Example |
|---|---|---|
| instant | Changes that must feel like direct manipulation | Checkbox tick, toggle knob |
| fast | Hover, press and focus feedback | Button background, row hover |
| normal | Surfaces entering or leaving | Popover, dropdown, toast |
| slow | Larger travel across the viewport | Drawer slide, dialog scale-in |
Reduced motion
prefers-reduced-motion is honoured globally
Under @media (prefers-reduced-motion: reduce) every duration token collapses to zero, so components change state instantly instead of animating. Nothing is lost: no meaning in this system is carried by motion alone.
If you add a custom animation, it must be defined with a duration token so it inherits this behaviour automatically.
Do & don't
Do
- Apply the ds-transition utility so timing and easing stay consistent.
- Keep entry and exit symmetrical — exits may be one step faster.
- Animate opacity and small transforms only.
- Let spinners and skeletons carry loading, not page-level animation.
Don't
- Do not animate colour on large surfaces — it reads as flicker.
- Do not stagger more than a handful of items.
- Do not use motion to draw attention to static content.
- Do not hardcode a millisecond value in a component.
Why it is designed this way
Short, token-driven motion keeps a data-dense product feeling responsive rather than animated. Routing everything through duration tokens is also what makes the reduced-motion contract enforceable: one media query disables the whole system's motion, with no component-by-component audit.