Key insights
- Proportions hold the shape together: make the rail twice the knob's diameter, and pad the knob by its own radius so it sits centered in both states.
- A good toggle morphs, it doesn't snap — animate the flip over ~250ms with an ease-out curve instead of jumping instantly between on and off.
- Four properties change at once during the flip: rail color, knob position (translateX), knob shadow, and the state label — all moving together, not in sequence.
- Build in accessibility: Space toggles the control when focused, a visible focus ring shows keyboard position, and aria-checked lets screen readers announce the state.
- For async toggles, go optimistic — flip immediately on click, spin a loader inside the knob while the request is pending, then roll back (with a shake and an error toast) if the server fails.
Do / Don't
- Do: Morph rail color, knob position, shadow, and label together over ~250ms with an ease-out curve.
- Do: Flip optimistically, show a spinner inside the knob while pending, and roll back on failure.
- Do: Support Space to toggle, a visible focus ring, and aria-checked for screen readers.
- Don't: Snap the knob instantly between states — the hard jump reads as broken, not responsive.
- Don't: Leave the toggle ambiguous during a network request — an un-spun switch looks stuck.
- Don't: Ship a toggle that only responds to a mouse click and skips keyboard and screen-reader users.