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 translate and colour, nothing else.Both are compositor-friendly. Animating left orwidth forces 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; theinstant row 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.

sm — settings, dense rows
md — default

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.

Idle.

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.