Apple Switch
Animated toggle switch inspired by iOS, with draggable thumb, liquid press feedback, spring physics, size presets, and tone variants.
Installation
File Structure
apple-switch.tsx
Usage
"use client";
import { useState } from "react";
import { AppleSwitch } from "@/components/unlumen-ui/apple-switch";
export default function Example() {
const [enabled, setEnabled] = useState(false);
return (
<AppleSwitch
checked={enabled}
onCheckedChange={setEnabled}
label="Auto sync"
description="Keep project data up to date."
/>
);
}API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
checked? | boolean | - | Controlled checked state. |
defaultChecked? | boolean | - | Initial checked state for uncontrolled usage. |
onCheckedChange? | (value: boolean) => void | - | Called when the switch is toggled. |
label? | React.ReactNode | - | Text or node rendered beside the switch. |
description? | React.ReactNode | - | Supporting text rendered below the label. |
labelSide? | "left" | "right" | "right" | Which side of the switch the label content sits on. |
size? | "sm" | "md" | "lg" | "md" | Switch size preset. |
tone? | "neutral" | "accent" | "neutral" | Colour treatment for the checked state. |
disabled? | boolean | false | Disables interaction. |
className? | string | - | Additional classes applied to the switch root. |
Notes
- Built as a native
<button role="switch">— no Radix dependency. Pointer capture is used so drags work even when the pointer leaves the element. - The thumb supports click-to-toggle and drag-to-slide. A drag of more than 3 px suppresses the subsequent click event to avoid double-toggling.
- Press feedback uses a "liquid" blur layer and a widening thumb driven by Motion springs (
grabProgress). The effect collapses on pointer release. - Track fill, glow, and thumb travel are all derived from a single
activeProgresstransform, keeping the animation in sync without imperative sequencing. - Size presets store track and thumb dimensions separately, so the thumb naturally stretches wider than it is tall on press without altering the track.
- The optional label wraps the switch in a
<label>element linked viaid/htmlFor, keeping accessibility correct without adding extra ARIA attributes.
Credits
Built by leo.
Keep in mind
Most components on this site are inspired by or recreated from existing work across the web. I'm not here to take credit; just to learn, experiment, and sometimes push things a bit further. If something looks familiar and I forgot to mention you, reach out and I'll fix that right away.