Skip to content

Switch

Labelled toggle with a hidden checkbox and the ARIA switch contract.

Primitive · form

Terminal window
npx shadcn@latest add https://ndigo.dev/r/switch.json

To use the shorter @ndigo/switch form, configure the namespace in components.json.

Source Target Type
registry/ui/switch/nd-switch.ts @ui/nd-switch/nd-switch.ts registry:ui
registry/ui/switch/nd-switch.css @ui/nd-switch/nd-switch.css registry:file

See this component rendered live on the live examples page.

Registry: Ndigo element foundation. Packages: @zag-js/switch@~1.47.0 (installed automatically).

<nd-switch> renders a labelled switch backed by a visually hidden checkbox, so the native form value and the ARIA switch contract stay intact. The element builds the label, input, control, thumb, and label span when the markup is just text.

<nd-switch checked>Notifications</nd-switch>

Authored parts also work:

<nd-switch>
<label data-part="root">
<input data-part="hidden-input" />
<span data-part="control"><span data-part="thumb"></span></span>
<span data-part="label">Notifications</span>
</label>
</nd-switch>
Attribute Type Description
checked boolean Controlled checked state; reflected by the element
disabled boolean Disable the switch
readonly boolean Keep the value but block changes
required boolean Mark the hidden checkbox required
invalid boolean Mark the hidden checkbox invalid
name string Form field name
  • nd-checked-change — detail: { checked: boolean }.

The label wraps the hidden checkbox and names it; the visible control is aria-hidden, and the checkbox carries the switch semantics. Space toggles when the checkbox has focus. Disabled switches block pointer and keyboard changes.

Import nd-switch.css after the tokens. The track uses the surface/accent tokens, the thumb translates on data-state="checked", and the focus ring uses the shared focus tokens.