Motion
Motion that explains, never decorates.
Every component animates through these utilities. None of them use a JavaScript animation library.
| Utility | Use for |
|---|---|
motion-pop | Popovers, menus, tooltips, select lists. Scales out of the trigger. |
motion-dialog | Dialogs. A small lift, no zoom. |
motion-sheet | Sheets. Slides in from its edge and follows a swipe. |
motion-fade | Backdrops and anything opacity-only. |
motion-control | Hover and press colour feedback. |
motion-swap | Label swaps inside a control, so its width never changes. |
motion-message | Messages under a control, like field errors. A short fade and drop. |
motion-thumb | Parts that slide between two places, like a switch thumb. |
motion-indicator | A marker that slides to the chosen item, like the tab underline. |
motion-panel | Content that swaps in place, like tab panels. A fade with a small shift. |
motion-toast | Toasts. Slides in from its edge, follows a swipe and moves the stack between deck and list. |
The rules
- The more often something is used, the less it animates. Menus and the command palette are near instant. Rare moments can be expressive.
- Keyboard input is never animated. Focus the menu button below, open it with Enter and close it with Esc: no transition. Click it instead and you get a short one.
- Durations are tokens: 120ms, 160ms, 220ms, with exits at 110ms.
- Exits are faster than entrances.
- Ease out, never ease in.
- Only opacity, scale and translate. No layout properties, ever.
- Popups grow from their trigger, starting at 96% rather than zero.
- Everything is interruptible. Click a menu trigger rapidly and it reverses smoothly.
- Tooltips in a group are instant after the first one.
- Reduced motion keeps the fade.
Tokens
--qui-duration-fast: 120ms;
--qui-duration-base: 160ms;
--qui-duration-slow: 220ms;
--qui-duration-exit: 110ms;
--qui-ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
--qui-pop-scale: 0.96;Change these once and every component follows.