Motion
Duration and easing tokens for animations and transitions.Overview
Motion serves two purposes: it makes interfaces easier to understand, and it makes them more pleasant to use. A panel animating open helps the eye track what changed and where new content sits in the layout. These moments reduce cognitive load and make the interface feel responsive.
At the same time, well-tuned motion gives an application a sense of craft and polish that users notice, even if they can't name it.
The design system provides duration and easing tokens that keep these moments consistent across your application.
Duration
Nine duration tokens in fast, medium, and slow bands.
Motion duration primitives. Three bands: fast (micro-interactions), medium (entrance/exit), slow (continuous). Min/max variants derive from base × ratio. A theme's motion.tempo (0.75–1.5) scales every one of them; a duration scale or an explicit token wins over it.
| Token | Value |
|---|---|
| --duration-fast-min | 130ms |
| --duration-fast | 175ms |
| --duration-fast-max | 230ms |
| --duration-medium-min | 310ms |
| --duration-medium | 410ms |
| --duration-medium-max | 550ms |
| --duration-slow-min | 730ms |
| --duration-slow | 975ms |
| --duration-slow-max | 1300ms |
Easing
One easing curve, --ease-standard.
Easing curves for animations and transitions. --ease-entrance and --ease-move follow a theme's motion.character: crisp decelerates without overshoot, expressive overshoots slightly, and at standard both equal --ease-standard. Exits keep their own curve at every character.
| Token | Value |
|---|---|
| --ease-standard | |
| --ease-entrance | |
| --ease-move |
Where Motion Helps
Some parts of the interface benefit from animation. Panels, dialogs, and collapsible sections are disorienting when they appear instantly, so animation gives the eye something to follow. Toasts and notifications need just enough entrance to be noticed without startling. State changes like a switch flipping or a selection highlighting feel more intentional with a brief transition.
The common thread is that these are moments where the user needs to understand what happened.
Where Motion Hurts
Table row hovers. List item highlights. Anything the user does dozens of times per minute. Adding perceptible duration to these interactions makes the interface feel like it's catching up to the cursor. Keep these fast enough that the user never notices a delay.
Animations 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. Motion should never stand between the user and their next action.
Movement Principles
- Not everything needs an animated exit. Elements the user is moving away from, such as tooltips, hover cards, and dropdown menus, can disappear instantly. The user has already shifted their attention. Animate the exit only when it helps orient the user, like a panel closing or a dialog dismissing to reveal what's underneath.
- When you do animate exit, match the entrance. A panel that slides in from the right should slide back out to the right.
- Direction should match the action. Navigating deeper into content should feel like moving forward. Going back should feel like returning. This keeps the user oriented in the structure of the application.
- Contextual UI should feel connected to its trigger. A dropdown should expand from the button that opened it. A popover should appear near the element it describes. This doesn't apply to global UI like command palettes or toasts, which have their own fixed positions.
Respecting User Preferences
Some users experience motion sensitivity; animation that feels polished to one person can cause discomfort for another. Astryx components already switch to instant changes when the OS reduced-motion setting is on. Do the same in your own animations with @media (prefers-reduced-motion: reduce).
Animate with motion tokens
Set transition durations and easing from the motion tokens, so a theme that retunes motion retunes your animations too. Ease something arriving on --ease-entrance and something moving on screen on --ease-move, so it follows the theme's character.
tsximport {durationVars, easeVars} from '@astryxdesign/core/theme/tokens.stylex';const styles = stylex.create({fadeIn: {transitionProperty: 'opacity',transitionDuration: durationVars['--duration-fast'],transitionTimingFunction: easeVars['--ease-standard'],},slideUp: {transitionProperty: 'transform, opacity',transitionDuration: durationVars['--duration-medium'],transitionTimingFunction: easeVars['--ease-entrance'],},});
Tune motion from the theme
A theme sets how motion feels with three knobs in defineTheme's motion. They drive the CSS motion tokens and the springs of touch motion from the same values, so both stay in step.
temposcales every motion duration: 1 is Astryx's own, 0.75 the quickest and 1.5 the slowest (values outside are clamped).charactersets how lively motion is:'crisp'gives the entrance and move curves no overshoot and takes some bounce out of springs,'standard'is Astryx's own, and'expressive'overshoots slightly on entrances and moves. Exits and fades keep their measured bounce at every character.reducedMotion: 'always'reduces motion for everyone, as if each person had turned on Reduce Motion. Not everything follows it yet: the theme's motion-keyed adaptation rules, the press release fade and the animator, with its layout glide and Reduce Motion fade, do, and components' other Reduce Motion styles don't yet.'system', the default, follows each person's setting. No value loosens Reduce Motion.
tsexport const brandTheme = defineTheme({name: 'brand',motion: {tempo: 0.85, character: 'crisp'},});
Some motion never follows the knobs, because it tracks a finger or the system: finger tracking, momentum and the rubber band, the on-screen keyboard, the press model's onset delay, cancel distance and tap flash (its release fade follows tempo), hover-intent delays, gesture thresholds, the loops of busy indicators such as Spinner and Skeleton, and the 200 ms Reduce Motion cross-fade.
Precedence, lowest to highest: the knobs, then a duration scale (fast, medium, slow, ratio) for the durations it sets, then explicit tokens. A theme with no motion renders exactly as before.
Best Practices
| Guidance | Practices |
|---|---|
| Do | Animate transitions that involve spatial change: panels opening, content expanding, elements entering the screen. |
| Do | Use fast tokens for small, frequent interactions. Use medium tokens for larger transitions that rearrange the layout. |
| Do | Honor reduced motion preferences at the OS level. |
| Don't | Let hover states or high-frequency interactions feel like they're lagging behind the user. |
| Don't | Let animation delay when a user can interact with new content. The transition should complete before (or not block) the next action. |
| Don't | Move elements in ways that contradict where they came from or where they're going. |