Glin UI
Primitive / Atom

Switch

On/off control built on Radix switch primitive.

Edit on GitHub

Email 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

Install from
pnpm dlx @glinui/cli@latest add switch

Prefer the package?

Usage

State matrix

Statesmmdlg
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

KeyAction
SpaceToggle 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

transform

API Reference

PropTypeRequiredDefaultDescription
checkedbooleanNo-Controlled on/off state.
defaultCheckedbooleanNo-Initial state.
onCheckedChange(checked: boolean) => voidNo-Change handler.
variantControlVariantPropNoambient (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).
sizeSwitchSizeNomd36x20, 44x24 or 52x28 track.
onIcon / offIconReactNode--Icon inside the thumb for each state, sized to the thumb.
showLabelsbooleanNofalseShow On/Off text inside the track (lg only). Customize with onLabel and offLabel.
loadingbooleanNofalseShows a spinner in the thumb, makes the switch inert and sets aria-busy.
label / descriptionReactNode--Renders a clickable label row with linked description.
activeColorstringNo-Custom checked color, applied as a CSS custom property.
name / value / required / formstring | boolean--Native form participation.
disabledbooleanNofalseDisables interaction.
descriptionReact.ReactNodeNo-Helper text under the label, linked through aria-describedby.
fieldClassNamestringNo-Class applied to the label row wrapper (only when label or description is set).
labelReact.ReactNodeNo-Field label. Renders a clickable label row.
namestringNo-Form field name submitted with form data.
offIconReact.ReactNodeNo-Icon shown inside the thumb when off (sized to the thumb).
offLabelstringNo"Off"Text for the off state when `showLabels` is set.
onIconReact.ReactNodeNo-Icon shown inside the thumb when on (sized to the thumb).
onLabelstringNo"On"Text for the on state when `showLabels` is set.
requiredbooleanNo-Marks the switch as required within a form.
valuestringNo-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.

Import

import { Switch } from "@glinui/ui"

Source Files

Dependencies

@glinui/ui

Generated API Snapshot

Beta

Auto-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

PropTypeRequiredDefaultDescription
activeColorstringNo-Custom checked color (any CSS color). Applied as a CSS custom property, no inline style.
checkedbooleanNo-Controlled checked state.
defaultCheckedbooleanNo-Initial checked state for uncontrolled usage.
descriptionReact.ReactNodeNo-Helper text under the label, linked through aria-describedby.
disabledbooleanNo-Prevents interaction and applies muted styling.
fieldClassNamestringNo-Class applied to the label row wrapper (only when label or description is set).
labelReact.ReactNodeNo-Field label. Renders a clickable label row.
loadingbooleanNofalseShows a spinner in the thumb, makes the switch inert and sets aria-busy.
namestringNo-Form field name submitted with form data.
offIconReact.ReactNodeNo-Icon shown inside the thumb when off (sized to the thumb).
offLabelstringNo"Off"Text for the off state when `showLabels` is set.
onCheckedChange(checked: boolean) => voidNo-Callback fired when the checked state changes.
onIconReact.ReactNodeNo-Icon shown inside the thumb when on (sized to the thumb).
onLabelstringNo"On"Text for the on state when `showLabels` is set.
requiredbooleanNo-Marks the switch as required within a form.
showLabelsbooleanNofalseRender "On"/"Off" text inside the track (large size only).
sizeSwitchSizeNo"md"Track and thumb size: sm 36x20, md 44x24, lg 52x28.
valuestringNo-Value submitted with the form when checked.
variantControlVariantPropNo-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.