pnpm dlx @glinui/cli@latest add switchEmail notifications
Choose what lands in your inbox.
When someone tags you in a thread.
A Monday summary of what shipped.
Immediate email when a build fails.
Occasional updates about new features.
Installation
pnpm dlx @glinui/cli@latest add switchPrefer the package?
Usage
State matrix
| State | sm | md | lg |
|---|---|---|---|
| Off | |||
| On | |||
| Disabled off | |||
| Disabled on |
import { Switch } from "@glinui/ui"
export function Demo() { return ( <div className="grid grid-cols-3 gap-4"> {(["sm", "md", "lg"] as const).map((size) => ( <div key={size} className="flex flex-col items-center gap-3"> <Switch aria-label="Off" size={size} /> <Switch aria-label="On" size={size} defaultChecked /> <Switch aria-label="Disabled" size={size} disabled /> <Switch aria-label="Disabled on" size={size} disabled defaultChecked /> </div> ))} </div> )}Variants
Each variant on and off. Pick a backdrop in the stage to check contrast.
import { Switch } from "@glinui/ui"
export function Demo() { return ( <div className="flex flex-wrap items-center gap-4"> <Switch variant="glinr" defaultChecked aria-label="glinr on" /> <Switch variant="glinr" aria-label="glinr off" /> <Switch variant="solid" defaultChecked aria-label="solid on" /> <Switch variant="solid" aria-label="solid off" /> <Switch variant="plain" defaultChecked aria-label="plain on" /> <Switch variant="plain" aria-label="plain off" /> <Switch variant="soft" defaultChecked aria-label="soft on" /> <Switch variant="soft" aria-label="soft off" /> <Switch variant="outline" defaultChecked aria-label="outline on" /> <Switch variant="outline" aria-label="outline off" /> <Switch variant="ghost" defaultChecked aria-label="ghost on" /> <Switch variant="ghost" aria-label="ghost off" /> </div> )}Glass (opt-in)
Glass needs a backdrop: it is shown here on a photo stage.
import { Switch } from "@glinui/ui"
export function Demo() { return <Switch variant="glass" defaultChecked />}Default Checked
import { Switch } from "@glinui/ui"
export function SwitchDefaultCheckedDemo() {
return (
<div className="flex items-center gap-2">
<Switch id="notifications" defaultChecked />
<label htmlFor="notifications" className="text-sm">Enable notifications</label>
</div>
)
}With Form Label
import { Switch } from "@glinui/ui"
export function SwitchFormDemo() {
return (
<div className="flex items-center justify-between rounded-lg border border-border/60 p-4">
<div className="space-y-0.5">
<p className="text-sm font-medium">Marketing emails</p>
<p className="text-sm text-neutral-500">Receive emails about new products and features.</p>
</div>
<Switch id="marketing" aria-label="Marketing emails" />
</div>
)
}Accessibility
- Built on Radix Switch with `role="switch"`.
- `label` and `description` wire `htmlFor` and `aria-describedby` for you.
- 44px minimum hit area; the thumb travels toward the inline end in RTL.
- Built on `@radix-ui/react-switch` which renders a native `button` with `role="switch"`.
- Associates with a visible `label` via `htmlFor` / `id` pairing, or via `aria-label` when no visual label element is present.
- Keyboard togglable with `Space` and `Enter`.
- `aria-checked` is managed automatically by the primitive.
Keyboard Interactions
| Key | Action |
|---|---|
| Space | Toggle the switch on/off. |
ARIA Attributes
- `role="switch"`
- `aria-checked`
- `aria-busy` while loading
Reduced Motion
The thumb slide and stretch are instant under `prefers-reduced-motion` and when `data-glin-motion` is `none` or `subtle`.
The thumb slide transition respects `prefers-reduced-motion` and removes the transform animation when enabled.
Affected properties
transformAPI Reference
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
checked | boolean | No | - | Controlled on/off state. |
defaultChecked | boolean | No | - | Initial state. |
onCheckedChange | (checked: boolean) => void | No | - | Change handler. |
variant | ControlVariantProp | No | ambient (glinr) | Track look. Omit to follow the ambient design style: glinr is an inset well with a raised accent fill, plain is the flat shadcn switch. Glass variants add a frosted track and liquid accent fill (opt-in). |
size | SwitchSize | No | md | 36x20, 44x24 or 52x28 track. |
onIcon / offIcon | ReactNode | - | - | Icon inside the thumb for each state, sized to the thumb. |
showLabels | boolean | No | false | Show On/Off text inside the track (lg only). Customize with onLabel and offLabel. |
loading | boolean | No | false | Shows a spinner in the thumb, makes the switch inert and sets aria-busy. |
label / description | ReactNode | - | - | Renders a clickable label row with linked description. |
activeColor | string | No | - | Custom checked color, applied as a CSS custom property. |
name / value / required / form | string | boolean | - | - | Native form participation. |
disabled | boolean | No | false | Disables interaction. |
description | React.ReactNode | No | - | Helper text under the label, linked through aria-describedby. |
fieldClassName | string | No | - | Class applied to the label row wrapper (only when label or description is set). |
label | React.ReactNode | No | - | Field label. Renders a clickable label row. |
name | string | No | - | Form field name submitted with form data. |
offIcon | React.ReactNode | No | - | Icon shown inside the thumb when off (sized to the thumb). |
offLabel | string | No | "Off" | Text for the off state when `showLabels` is set. |
onIcon | React.ReactNode | No | - | Icon shown inside the thumb when on (sized to the thumb). |
onLabel | string | No | "On" | Text for the on state when `showLabels` is set. |
required | boolean | No | - | Marks the switch as required within a form. |
value | string | No | - | Value submitted with the form when checked. |
Source
Import directly from the package or browse the source on GitHub. Click any file to view it.
Generated API Snapshot
Beta
Generated API Snapshot
BetaAuto-extracted from TypeScript source in packages/ui/src/components/switch.tsx. This section is in beta and may lag behind hand-curated docs. Regenerate with pnpm --filter @glinui/docs api:generate.
Generated: 2026-10-08T01:41:21.546Z · Full index: /docs/api-metadata
Primary Props Type
SwitchProps
SwitchProps
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
activeColor | string | No | - | Custom checked color (any CSS color). Applied as a CSS custom property, no inline style. |
checked | boolean | No | - | Controlled checked state. |
defaultChecked | boolean | No | - | Initial checked state for uncontrolled usage. |
description | React.ReactNode | No | - | Helper text under the label, linked through aria-describedby. |
disabled | boolean | No | - | Prevents interaction and applies muted styling. |
fieldClassName | string | No | - | Class applied to the label row wrapper (only when label or description is set). |
label | React.ReactNode | No | - | Field label. Renders a clickable label row. |
loading | boolean | No | false | Shows a spinner in the thumb, makes the switch inert and sets aria-busy. |
name | string | No | - | Form field name submitted with form data. |
offIcon | React.ReactNode | No | - | Icon shown inside the thumb when off (sized to the thumb). |
offLabel | string | No | "Off" | Text for the off state when `showLabels` is set. |
onCheckedChange | (checked: boolean) => void | No | - | Callback fired when the checked state changes. |
onIcon | React.ReactNode | No | - | Icon shown inside the thumb when on (sized to the thumb). |
onLabel | string | No | "On" | Text for the on state when `showLabels` is set. |
required | boolean | No | - | Marks the switch as required within a form. |
showLabels | boolean | No | false | Render "On"/"Off" text inside the track (large size only). |
size | SwitchSize | No | "md" | Track and thumb size: sm 36x20, md 44x24, lg 52x28. |
value | string | No | - | Value submitted with the form when checked. |
variant | ControlVariantProp | No | - | Track look. Omit to follow the ambient design style (glinr = inset well track with a raised accent fill). Also: solid, plain, soft, outline, ghost, glass (opt-in, liquid fill), liquid, matte, frosted. |