A control that allows the user to toggle between checked and not checked.
Installation
Install the packages
Add the shadcn/ui component
Animate it
The CLI finds your shadcn/ui components through components.json, swaps their primitive imports for Animate UI's and removes the CSS animation classes Motion replaces.
Usage
Import the primitive from Animate UI instead of Base UI. Everything else stays the same.
import { Switch } from '@animate-ui/react/primitives/base-ui/switch';
export function AirplaneMode() {
return (
<label className="flex items-center gap-2">
<Switch.Root>
<Switch.Thumb />
</Switch.Root>
Airplane mode
</label>
);
}Using the @base-ui/react umbrella import instead? The barrel mirrors it: import { Switch } from '@animate-ui/react/primitives/base-ui'.
Switch.Root.Props, Switch.Thumb.State and the other type namespaces are kept.
Animation
The motion of Animate UI v1's switch:
- Thumb, pressed: stretches toward the middle of the track, its other edge in place. Its width grows by 3/16 (a 16px thumb becomes 19px, v1's
pressedWidth) on a spring (stiffness 300, damping 25). It's the thumb's real width, so its round ends stay round. - Thumb, on a change: springs to its new side while its width springs back, on the same spring (v1's
layoutanimation). The thumb'stranslateclasses still decide where it rests (data-checked:translate-x-…): Animate UI puts it back where it was with atransformand springs it to its new place. - Root doesn't move. Its colours are the component's CSS, and v1's track changed colour at once: shadcn/ui's
transition-allon the track would fade it, so the CLI removes it. - The press is v1's: the pointer, or Enter on the keyboard. Space toggles without the stretch, and the thumb glides the same way.
- Toggling again mid-glide turns back from where the thumb is, without a jump.
- Under reduced motion, the thumb jumps to its side, without the stretch.
- shadcn/ui's
transition-transformon the thumb would tween itstranslate; the CLI removes it too (Animate UI also skips it while measuring, so a leftover class doesn't break the glide).
API Reference
Every part takes exactly the props of Base UI's Switch. Animate UI adds the animation props below. A render element (or function) of your own gets Base UI's behaviour: a Root rendered that way has no press stretch, a Thumb no animation.
Root
Base UI props. The Root doesn't animate itself: it tells the Thumb when it's pressed.
Thumb
Base UI props, plus:
| Prop | Type | Default |
|---|---|---|
transition? | Transition | { type: 'spring', stiffness: 300, damping: 25 } |
AnimateUIProvider's tempo scales the spring with everything else.