Skip to content
Alea0.1
Pro
  1. Alea
  2. Motion
  3. Motion system

Motion

Motion system

Every animation in Alea is one of 33 patterns, built only from the motion tokens. Motion explains what changed: where something came from, where the selection went, that a press was heard. With reduced motion, nothing travels; things still fade.

Change it, at three levels

Every component has a sensible default. You decide where motion goes and which one, without forking anything.

  1. The whole app: ThemeProvider motion sets the mode (expressive, productive, reduced or off), follows or overrides the OS reduced motion setting, scales speed and intensity, and changes the default per component type.
  2. One component type, in CSS: .alea-popover { --alea-enter: alea-m-fade-in; --alea-exit: alea-m-fade-out; }. These variables don't inherit, so a dialog never leaks its motion into the select inside it.
  3. One instance: every overlay takes a motion prop: a preset, false, or { enter, exit, duration, easing, delay }. See it live.
<ThemeProvider motion={{
mode: 'productive', // expressive (default) | productive | reduced | off
reduced: 'system', // follow the OS (default) | 'always' | 'never'
speed: 0.9, // multiplies every duration
intensity: 1.2, // multiplies distances, scales and blur
components: { dialog: 'scale', tooltip: 'fade', toast: { enter: 'slide-left', duration: 300 } },
}}>
<Select motion="blur" />
<DialogModal motion={{ enter: 'zoom', duration: 320, easing: 'spring' }} />
<Popover motion={false} />

Presets: fade, scale, pop, rise, drop, slide-up, slide-down, slide-left, slide-right, blur, zoom, flip, morph, none. Each is a pair of keyframes, alea-m-<preset>-in and -out, that you can also use in your own CSS.

Modes

Try the same controls in each mode. Productive is shorter and quieter, for dense apps; reduced keeps fades and drops travel; off removes every animation.

Hover me

Patterns

The button at the bottom of the screen plays the automatic demos again; the rest you can try by hand.

Pop pop

Anchored overlays grow out of what opened them, from the side they open on, and shrink away faster than they came.

Used by
Popover, Select, ComboBox, Autocomplete, menus, date pickers, HoverCard, Tooltip, NavigationMenu
Tokens
duration-base in, duration-fast out, scale-from, distance-sm, ease-out / ease-in

Rise rise

Page-level overlays come up a little while the backdrop fades. Toasts rise with a small overshoot and leave to the side.

Used by
Dialog, AlertDialog, CommandPalette, Toast, Tour
Tokens
duration-slow, distance-lg, ease-out; toasts ease-emphasized

Slide slide

Panels come in from their edge and go back the same way.

Used by
Drawer, bottom sheets, the mobile navigation
Tokens
duration-slow in, duration-base out

Stagger stagger

The items of a list that just opened arrive one after another, so the eye reads them top down. Only the first twelve wait.

Used by
Options, menu items, command results
Tokens
stagger (40 ms), distance-sm, duration-base

Expand expand

Content opens to its own height, then fades in, so the layout below moves smoothly.

Used by
Accordion, Spoiler, Tree, NavigationMenu panels
Tokens
duration-slow, ease-out

Glide glide

One indicator per group moves to the new item and takes its size, with a slight overshoot. You see where the selection went.

Used by
Tabs, SegmentedControl, ToggleGroup
Tokens
duration-base, ease-emphasized

Hover me

It rises 4 px.

Lift lift

Surfaces you can click rise a little and cast a deeper shadow on hover.

Used by
Interactive Card, Kanban cards, image tiles, FloatButton
Tokens
lift (-4 px), duration-base

Press press

Controls shrink slightly while pressed and spring back, so a tap feels answered.

Used by
Button, IconButton, toggles, tags, pagination, editor tools, bottom navigation
Tokens
scale-press (0.96), duration-instant

Morph morph

An icon turns into its other state instead of swapping: chevrons rotate, checks pop in, the burger becomes a close icon, switches spring.

Used by
Select, Accordion, Tree, Checkbox, Radio, Switch, Rating, Burger, ThemeToggle
Tokens
duration-base, ease-emphasized
tokens.json
theme.css
icons.svg

Tint tint

Hover and selection colors fade in very quickly; fast enough to feel instant, soft enough not to flicker.

Used by
Options, menu items, rows, links, sidebar and navigation links
Tokens
duration-instant

Nudge nudge

A field that turns invalid shakes once, with the error text, so the problem is found without hunting.

Used by
TextField, Select, pickers, TextArea
Tokens
distance-sm, duration-slow

Draw draw

Strokes and bars grow into place: progress, steps and chart lines.

Used by
ProgressBar, Meter, Steps, charts
Tokens
duration-slow / slower, ease-out

Pulse pulse

Something live or new breathes slowly. It stops with reduced motion.

Used by
Badge dot, Avatar status, Indicator
Tokens
1.6 s loop, ease-out

Shimmer shimmer

A sheen sweeps over placeholders while content loads.

Used by
Skeleton
Tokens
1.6 s loop (3 s with reduced motion)

Swap swap

Text or an icon changes with a short blur crossfade, so you notice the new word without a jump.

Used by
TextSwap: button labels (Save to Saved), status text, plan names
Tokens
duration-base in, duration-fast out, blur-sm, distance-sm

Roll roll

Digits roll to the new number, so a change in value reads as a change, not a flicker.

Used by
NumberRoll: prices, counters, stats, cart count
Tokens
duration-slow, ease-emphasized

Badge pop badge

A count pops with a small spring when it changes (not on the first render).

Used by
CountBadge, notification dots
Tokens
duration-base, ease-emphasized, scale-from

Success success

The busy state turns into a check that draws itself, then goes back to the label.

Used by
Button isSuccess after isLoading: save, submit, copy
Tokens
duration-slow, ease-out
TokensMotionFigma

Dissolve dissolve

Removed things blur, shrink and fade before they leave, so you see what went away.

Used by
Presence: tags, list rows, files, a cleared search
Tokens
duration-base, blur-md, ease-in

Alea Motion animates what changed.

Resize resize

When content grows or shrinks, the box animates to its new height instead of jumping.

Used by
AutoHeight: cards that grow, panels, read more
Tokens
duration-base, ease-out

Fan fan

Overlapping items spread apart on hover or focus, so each one can be seen.

Used by
AvatarGroup fan
Tokens
duration-base, ease-emphasized, lift

Ripple ripple

Press feedback grows from where you pressed (optional, off by default).

Used by
Button ripple, useRipple for your own elements
Tokens
duration-slower, ease-out
Press and hold to confirm

Hold hold

Holding fills a bar; the action runs only when it is full. Letting go cancels.

Used by
HoldButton for destructive actions
Tokens
1200 ms by default, linear

Hint hint

An arrow nudges toward where a link goes, on hover and keyboard focus.

Used by
Standalone links with an icon, .alea-hint
Tokens
duration-base, ease-emphasized, 3 px

Tokens

Components

Motion

Reveal reveal

Sections enter as they scroll into view, children one after another. Content that starts on screen, or without JavaScript, is never hidden.

Used by
Reveal, data-stagger, landing sections
Tokens
duration-slow, distance-lg, stagger

See the bar at the very top of this page as you scroll.

Scroll scroll

A bar fills as you read; a header can hide while scrolling down and come back on the way up.

Used by
ScrollProgress, useScrollDirection, Navbar
Tokens
CSS scroll timeline where supported

Thinking…

Stream stream

Streamed text fades in by chunk with a caret; a shimmer says the model is thinking.

Used by
StreamingText, .alea-text-shimmer, AI answers
Tokens
duration-slow, blur-sm

Stack stack

Toasts pile up behind the newest one and fan out on hover or keyboard focus, so many notifications never cover the page.

Used by
ToastProvider stacked
Tokens
duration-base, ease-out, 10 px and 5% per layer

Open a toast with the Stack demo and drag it sideways.

Swipe swipe

Drag a toast sideways to dismiss it: past 80 px or with a quick flick it leaves, otherwise it springs back. The close button stays for everyone else.

Used by
Toast
Tokens
duration-base, ease-out

Loading loading

Something is working: a spinner turns, a bar sweeps when there is no percentage. They keep moving with reduced motion because they carry meaning; everything decorative stops.

Used by
Spinner, ProgressBar and ProgressCircle without a value, Button isLoading, LoadingOverlay
Tokens
0.8 s turn, 1.4 s sweep
Downloads
12,840

Count count

A number counts up to its value when it first appears, so a stat reads as a result. Screen readers get the final number at once.

Used by
Statistic animate, NumberRoll for later changes
Tokens
duration-slower, ease-out

Ambient ambient

Slow, quiet movement in the background gives a surface life without asking for attention: orbs drift, a dot breathes, an aurora shifts. It stops completely with reduced motion.

Used by
OrbBackground, GradientDot, Aurora (Pro)
Tokens
18 to 26 s loops

Move between pages of these docs: they crossfade.

Route route

Page changes crossfade, slide or zoom with the View Transitions API (fade by default).

Used by
startViewTransition, React Router viewTransition, data-route-motion on <html>
Tokens
duration-fast out, duration-base in

Easings

--alea-motion-ease-out
cubic-bezier(0.16, 1, 0.3, 1)
--alea-motion-ease-in-out
cubic-bezier(0.65, 0, 0.35, 1)
--alea-motion-ease-standard
cubic-bezier(0.2, 0, 0, 1)
--alea-motion-ease-emphasized
cubic-bezier(0.34, 1.56, 0.64, 1)
--alea-motion-ease-in
cubic-bezier(0.4, 0, 1, 1)

Durations, distances and scales

--alea-motion-duration-instant120ms
--alea-motion-duration-fast200ms
--alea-motion-duration-base320ms
--alea-motion-duration-slow480ms
--alea-motion-duration-slower720ms
--alea-motion-distance-sm8px
--alea-motion-distance-md12px
--alea-motion-distance-lg24px
--alea-motion-scale-from0.92
--alea-motion-scale-press0.96
--alea-motion-stagger40ms
--alea-motion-lift-4px

Reduced motion

  • Distances, scales, the lift and the stagger go to zero: overlays and items fade in place, nothing travels across the screen.
  • Slow durations shorten to base; the emphasized curve stops overshooting.
  • Decorative loops stop (pulse, orbs, the indicator ping); the skeleton shimmer slows to 3 s. Spinners keep turning because they tell you something is happening.
  • Nothing important waits for an animation: exits finish under 200 ms, and focus moves at once.

Rules for new components

  • Use a pattern; if none fits, add one here first. Never a one-off keyframe.
  • Enter with ease-out, exit with ease-in and faster than the entrance.
  • Fade from 0.01, not 0, so the first paint counts.
  • Only animate transform and opacity (and height for expand): no layout jank.
  • In Figma, the same patterns are interactive components with Smart Animate on the ease-out curve.