Checkbox
SVG path morphing — a checkmark that draws itself in, plus the indeterminate state most libraries get wrong.
Checked
Disabled
Checkbox knobs
ms
ms
ms
How this works
A faded-in checkmark looks like it just appeared out of nowhere. A drawn checkmark — one that traces its own path from tail to tip — looks like it was just confirmed. That distinction is the entire point of this component: the same visual end-state, told with a different verb.
- Fill duration
- How long the box takes to go from empty (surface) to filled (accent). This is a plain color transition, not a spring — color isn't a position in space, so it doesn't need physics, just to be fast and consistent. At 50ms it's nearly a snap; at 250ms the fill visibly lags behind your click.
- Checkmark draw duration
- How long the checkmark takes to trace itself, using the SVG `pathLength` property animated from 0 to 1. At 50ms it reads almost as a flash; at 300ms you can clearly watch the stroke travel from the bottom of the check to the top — past that, it starts to feel like the interface is stalling rather than confirming.
- Fill → draw delay
- The gap between the box starting to fill and the checkmark starting to draw. At 0ms both happen at once, which reads as slightly busy — two things changing in the same instant. The default, 30ms, lets the eye register 'the box is filling' a beat before 'and now it's confirmed,' which is what makes the sequence feel considered rather than simultaneous.
- Indeterminate
- A parent 'select all' checkbox with some-but-not-all children checked. It gets its own icon (a horizontal dash) rather than a half-drawn checkmark, because a half-checkmark reads as a rendering glitch, not a deliberate third state. The dash uses the exact same fill + draw timing as a full check — it's a distinct icon, not a lesser one.
- Why the checkbox stays a real <input>
- The visible box is decoration layered on top of a real, native `<input type="checkbox">` that's stretched over it and made invisible. Screen readers, keyboard Space-to-toggle, and form submission all keep working exactly like a plain checkbox, because as far as the browser is concerned, that's all this is.
- Reduced motion
- With prefers-reduced-motion on, the checkmark and dash stop 'drawing' and instead just crossfade in and out by opacity — same information, no motion to trigger discomfort.