Inputs
Switch
A toggle for settings that take effect immediately, like turning on two-factor sign-in or auto-reminders. It comes in three sizes, can show its label and a description, and stays a plain button with role="switch" underneath.
Email clients 3 days before and after the due date.
Adds a Pay now button to every invoice.
A Monday digest of paid and overdue invoices.
<div className="mx-auto w-full max-w-md divide-y divide-line rounded-ui-lg border border-line bg-surface shadow-ui"> <div className="p-4"> <Switch labelPosition="start" label="Payment reminders" description="Email clients 3 days before and after the due date." defaultChecked /> </div> <div className="p-4"> <Switch labelPosition="start" label="Accept card payments" description="Adds a Pay now button to every invoice." defaultChecked /> </div> <div className="p-4"> <Switch labelPosition="start" label="Weekly summary" description="A Monday digest of paid and overdue invoices." /> </div></div>Usage
components/ui/switch.tsx
import { Switch } from "@/components/ui/switch"; export function Example() { return <Switch label="Auto-send reminders" showLabel defaultChecked />;}Examples
Settings list
Email clients 3 days before and after the due date.
Adds a Pay now button to every invoice.
A Monday digest of paid and overdue invoices.
<div className="mx-auto w-full max-w-md divide-y divide-line rounded-ui-lg border border-line bg-surface shadow-ui"> <div className="p-4"> <Switch labelPosition="start" label="Payment reminders" description="Email clients 3 days before and after the due date." defaultChecked /> </div> <div className="p-4"> <Switch labelPosition="start" label="Accept card payments" description="Adds a Pay now button to every invoice." defaultChecked /> </div> <div className="p-4"> <Switch labelPosition="start" label="Weekly summary" description="A Monday digest of paid and overdue invoices." /> </div></div>Sizes
<div className="flex items-center justify-center gap-6"> <Switch size="sm" label="Small" defaultChecked /> <Switch size="md" label="Medium" defaultChecked /> <Switch size="lg" label="Large" defaultChecked /></div>Visible label
label is always the accessible name. Add showLabel to print it next to the switch.
<div className="mx-auto flex w-fit flex-col gap-4"> <Switch label="Show archived clients" showLabel /> <Switch label="Round totals to whole numbers" showLabel defaultChecked /></div>Disabled
Available on the Business plan.
Required by your organisation.
<div className="mx-auto flex w-fit flex-col gap-4"> <Switch label="Single sign-on" description="Available on the Business plan." disabled /> <Switch label="Two-factor sign-in" description="Required by your organisation." disabled defaultChecked /></div>Props
PropTypeDefaultDescription
labelrequiredstringdefault: —Accessible name; also the visible label with showLabel or description.showLabelbooleandefault: falsePrint the label next to the switch.descriptionReactNodedefault: —Second line under the label. Implies showLabel.labelPosition"end" | "start"default: "end"start puts the label first and spreads the row, for settings lists.checked / defaultCheckedbooleandefault: falseControlled or initial state.onChange(on: boolean) => voiddefault: —Called with the new state.size"sm" | "md" | "lg"default: "md"Track 28, 36 or 44px wide.disabledbooleandefault: —Prevents toggling and dims the row.namestringdefault: —Submits “on” under this name when checked.idstringdefault: —Id of the switch button. Generated when omitted.
Accessibility
- A <button role="switch"> with aria-checked: Space and Enter toggle it, and screen readers say “on” or “off”.
- When the label is visible it's a real <label> linked by aria-labelledby, and clicking it toggles the switch.
- The description is linked with aria-describedby.
- Use a switch only for changes that apply immediately; inside a form that needs a Save button, use a Checkbox.
- The thumb position, not only the track color, shows the state, so it reads in every accent.