Switch
A binary on/off control. The knob stretches under the throw, slams into the far end of the track and shoves it outward, and latching on flings a small burst of sparks.
Usage
<Switch
size="md"
intensity="normal"
spring="bouncy"
label="Notifications"
/>How the motion works
The same construction as Tabs, on a body that only ever moves between two stops. Each edge of the knob runs its own spring toward the corresponding side of the target stop, so the knob's width is never animated — it is whatever the two edges happen to be apart on that frame. Throwing the switch kicks both outward along the axis of travel, the trailing edge dragged backwards and the leading edge lunging ahead, so the knob elongates under the force and pulls closed as it arrives; what it gains in width it gives back in height. The obvious alternative, a scaleX read off velocity, flattens the knob's ends into an ellipse, whereas here the geometry is real and the radius is simply half the height, so the ends stay circular however far it stretches. The tug is authored in pixels of excursion and converted into the velocity that produces that excursion on whichever spring the component was handed — without that inversion a loose preset flings the edges several times further than a stiff one and no constant holds across presets. The track's end caps are only ever moved by contact, and a switch touches both on every throw: the knob is already resting against the cap it leaves, so that shove lands immediately, while the impulse for the far cap is parked until the leading edge has actually crossed the track and only then released. Caps move by inset rather than scaleX so they stay circular instead of shearing into ellipses, and widening the track pinches it vertically, so it reads as one skin under tension rather than a box that got bigger. Both caps are hard-floored at the knob's penetration depth — the track can never be narrower than the thing inside it, so a big enough overshoot pushes the cap ahead of its own spring rather than escaping it, and once the cap stops conceding ground the knob compresses against it instead, which is what a soft body pinned to a stop does. The track's colour is taken from where the knob's centre actually is rather than from a parallel progress value, so the recolour cannot drift out of step with the throw; it is clamped for the mix, because a colour interpolated past either endpoint is not a colour, while the position it is read from is left free to ring. Sparks decay rather than travel: one overdamped spring falls from 1 to 0 and every spark reads its whole life off that single value, so the burst cannot ring back toward the knob and look tethered. Each spark is a capsule with a lead tip and a trail end, eased out of that shared value at different rates — the lead end reaches its distance quickly while the trail end starts near the anchor and only rushes to catch up near the end, so the gap between them draws the spark out into a rounded-rectangle streak on the way out and closes it back to a dot on the way in, the same lead/lag construction as the knob's own stretch. The burst is anchored just outside the track's own top-right corner rather than a point inside it, so it originates outside the shell instead of over it. They fire only on the latching edge — a control that threw the same celebration on being switched off would be spending emphasis on the direction that does not need it.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| checked | boolean | — | Controlled state. Omit for uncontrolled use. |
| defaultChecked | boolean | false | Initial uncontrolled state. |
| onChange | (checked: boolean) => void | — | Fires on every toggle. |
| size | "sm" | "md" | "lg" | "md" | Track and knob dimensions. |
| spring | SpringLike | "bouncy" | Drives both knob edges and both end caps. |
| intensity | "subtle" | "normal" | "strong" | "normal" | Scales the stretch and the shove the caps take. |
| label | string | — | Accessible name for the switch. |
