Components · Lab
Toggle motion
A bench for the switch's slide. Every specimen is the real control — same token geometry, samepeer-checked mechanics — differing only in its transition, so what wins here transfers totransition-switch unchanged.
What a toggle's motion has to do
- Confirm, don't perform. The user already knows what they did — they did it. The slide exists to show which state you landed in, so it should be over before it draws attention to itself. 100–200ms is the working range; past 250ms the control feels behind you.
- Animate
translateand colour, nothing else.Both are compositor-friendly. Animatingleftorwidthforces layout on every frame. - Ease out, don't overshoot. Fast off the mark and settling is right for a control that has arrived somewhere. Overshoot needs clearance the track does not have — 2px each side.
- No JavaScript. Nothing here needs a library, and a per-frame JS driver competes with whatever else is hydrating. The last bench makes that measurable.
- Respect reduced motion. The shipped control inherits the app-wide preference; the
instantrow below is what that collapses to.
What ships today
transition-switch — 150ms fast, ease-out decelerate, on translate. Change it in one place (global.css) and every switch in the app follows.
Every curve, side by side
Flip them together — differences between easings are almost invisible one at a time and obvious in parallel. Watch the landing, not the start: that is where a curve gives itself away.
decelerate
ease-out — the current default. Fast off the mark, settles softly.
standard
ease-in-out. Symmetrical; can read slightly sluggish at the start.
accelerate
ease-in. Wrong shape here — it hesitates, then rushes the landing.
emphasized
Sharp in-out. Snappy, deliberate; a bigger gesture than a toggle needs.
spring
Overshoots ~10%. The track has 2px of clearance, so the thumb clips the edge.
linear
No easing. Mechanical — useful only as a baseline to compare against.
out-quadnot a token
Gentler ease-out than decelerate. NOT A TOKEN yet.
out-back-softnot a token
Spring with the overshoot dialled down (~4%). NOT A TOKEN yet.
Every duration, one curve
Duration decides whether a toggle feels like your action or the app's. Compare against instant — if a duration cannot beat no-animation-at-all, it is decoration.
instant · 0ms
No animation. The honest floor — is motion even earning its place?
snappy · 75ms
Near-instant. Reads as a hard state flip.
fast · 150ms
The current default. Visible slide, still immediate.
base · 250ms
The previous default — slow enough that the control feels behind you.
slow · 400ms
Clearly too slow for a toggle. Included as the upper bound.
Main thread under load
Turn the load on, then flip the switch. A translate transition is composited, so it should stay smooth while the page stutters around it — which is exactly what a JS-driven animation could not do here.
Curves marked not a token are candidates only. If one wins it has to be added totokens/core.json and rebuilt before it can ship — DESIGN.md Rule 9, no exceptions for motion.