Switch
An on/off control whose thumb settles with a double bounce.
Installation
npx shadcn@latest add @loomui/switchUsage
import { Switch } from "@/components/ui/switch"// Uncontrolled
<Switch defaultChecked aria-label="Auto-send" />
// Controlled
<Switch checked={autoSend} onCheckedChange={setAutoSend} aria-label="Auto-send" />How it works
The thumb's travel distance is never a magic number — --travel is calc()d
from the track width, thumb diameter, and padding, so resizing any of those
custom properties keeps the thumb landing exactly on the track's edge.
The bounce only plays once the switch has actually been clicked. A fresh
data-checked — from defaultChecked, a controlled checked prop, anything
that isn't a click — renders in its final position immediately, with no
data-interacted attribute yet, so nothing animates. The first click sets
data-interacted and it stays set, so every toggle after that — click-driven
or prop-driven — eases the thumb past its resting spot and settles back,
rather than snapping straight there.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | - | Controlled state. Omit for uncontrolled. |
defaultChecked | boolean | false | Initial state when uncontrolled. |
onCheckedChange | (checked: boolean) => void | - | Fires after every toggle. |
className | string | - | Merged onto the track button. |
Any other <button> prop is forwarded, including disabled.
Reduced motion
The track and thumb still move to their new state — it's not decorative, it's the control's whole job — just as an instant cut instead of an eased bounce.