Skip to content
Nizivo UI

Switch

An on or off setting that applies at once, drawn as a track and thumb. A native checkbox with role switch, so it submits with the form before hydration.

Tier: client

Import

import { Switch } from '@nizivo/react/switch';

// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css
import '@nizivo/react/css/switch.css';

Static or interactive

Client. It always ships its client leaf, which wires it to a Field, and inside a Field also FieldScope. The server HTML is a native checkbox with role="switch", so it toggles and submits before hydration. How to choose.

Invalid

With an error, an unchecked Switch draws a 1 px --nz-border-critical ring inside its track (--nz-border-width-default), as every Figma border is 1 px; the message under it, with its icon, carries the state. The checked track keeps its brand fill.

Examples

Basic

A native checkbox with role="switch": it submits value (default "on") while on.

import type { JSX } from 'react';
import { Switch } from '@nizivo/react/switch';

export function SwitchExample(): JSX.Element {
  return (
    <Switch name="online-store" defaultChecked>
      Online store
    </Switch>
  );
}

States

Settings that apply together sit in a Fieldset; off, on and both disabled states.

Billing emails
Sent to the billing contact.
import type { JSX } from 'react';
import { Fieldset } from '@nizivo/react/fieldset';
import { Switch } from '@nizivo/react/switch';

export function SwitchStatesExample(): JSX.Element {
  return (
    <Fieldset legend="Billing emails" description="Sent to the billing contact.">
      <Switch name="billing" value="invoices" defaultChecked>
        Invoices
      </Switch>
      <Switch name="billing" value="usage">
        Usage reports
      </Switch>
      <Switch name="billing" value="failed" defaultChecked disabled>
        Failed payments (always on)
      </Switch>
      <Switch name="billing" value="digest" disabled>
        Weekly digest (unavailable)
      </Switch>
    </Fieldset>
  );
}

Field

Inside a Field: the Field label and description name and describe the switch.

Show wholesale prices to approved buyers.
Set a wholesale price list first.
import type { JSX } from 'react';
import { Field } from '@nizivo/react/field';
import { Switch } from '@nizivo/react/switch';

export function SwitchFieldExample(): JSX.Element {
  return (
    <Field
      label="Wholesale"
      description="Show wholesale prices to approved buyers."
      error="Set a wholesale price list first."
    >
      <Switch name="wholesale">Enable wholesale</Switch>
    </Field>
  );
}

Props

className and style go on the root <label>; every other attribute, ref included, goes on the native <input>. With name, the form submits value (default "on") while the switch is on.

Client component Renders data-slot="switch" with the class nz-switch. Props: SwitchProps. Source: src/switch/switch.client.tsx.

NameTypeDefaultDescription
checkedboolean–

Controlled state: on or off.

childrenReactNode–

The label, after the track. Without one, name the switch with aria-label.

defaultCheckedbooleanfalse

Uncontrolled initial state.

invalidboolean–

An error message is presented for this switch. Inside a Field, the Field decides.

onCheckedChange(checked: boolean, details: ChangeDetails<SwitchChangeReason>) => void–

Called after the consumer's own onChange, unless it called preventDefault().

renderRenderProp<SwitchState>–

Composition of the root <label>, the hit target.

  • Also takes every attribute of <input> except children, readOnly, role, size, type; checked, defaultChecked are redeclared above. (Omit<ComponentPropsWithRef<"input">, "type" | "role" | "children" | "readOnly" | "size">)

render takes an element, or, in client code, a function of the props and this state (SwitchState):

NameTypeDefaultDescription
disabledrequiredboolean–
invalidrequiredboolean–

An error message is presented (the Field's, or the invalid prop).

requiredrequiredboolean–

Other exports

SwitchChangeReason type

import type { SwitchChangeReason } from '@nizivo/react/switch'

Every change comes from the native change event: a click, Space, or a click on the label.

type SwitchChangeReason = "input"

SwitchProps type

import type { SwitchProps } from '@nizivo/react/switch'

The props of Switch, listed above.

SwitchState type

import type { SwitchState } from '@nizivo/react/switch'

What a render function receives for the root <label>.

The render state of Switch, listed above.

Data attributes and slots

Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.

SlotRendered byData attributes
switch
.nz-switch
Switch
root (takes render)
  • data-disabled (present or absent) ← disabled
    Mirrors the disabled attribute
  • data-invalid (present or absent) ← invalid
    An error message is currently presented (not "fails constraints"); always the Field's own state, never the engine's
  • data-required (present or absent) ← required
    Mirrors the required attribute
switch-input
.nz-switch-input
Switch
inner element (CSS only); interactive, focus: self; forced colours: border, fill on :checked
none
switch-label
.nz-switch-label
Switch
inner element (CSS only)
none
switch-thumb
.nz-switch-thumb
Switch
inner element (CSS only); forced colours: mark
none

CSS hooks

Set a hook on the component's class or any ancestor to restyle it without specificity games; leave it unset for the default shown.

HookDefaultRead as
--nz-switch-accent--nz-bg-brand
  • --_nz-switch-bg on .nz-switch-input:checked
--nz-switch-gap--nz-space-2
  • column-gap on .nz-switch
--nz-switch-thumb-bg--nz-bg-surface
  • background on .nz-switch-thumb
--nz-switch-thumb-shadow--nz-elevation-1
  • box-shadow on .nz-switch-thumb

Layers: nz.components. Classes: .nz-switch, .nz-switch-input, .nz-switch-label, .nz-switch-thumb.

Tokens this stylesheet reads (19)

--nz-bg-brand, --nz-bg-brand-muted, --nz-bg-disabled, --nz-bg-surface, --nz-border-control, --nz-border-control-hover, --nz-border-critical, --nz-border-width-default, --nz-duration-fade, --nz-duration-spring, --nz-easing-spring, --nz-easing-standard, --nz-elevation-1, --nz-font-body-m, --nz-radius-full, --nz-space-0-5, --nz-space-2, --nz-text-disabled, --nz-text-primary

Accessibility

These parts are interactive. Each gets the focus outline and touch-action rule from @nizivo/react/css/base.css (the nz.base layer), so the floor survives a restyle:

  • switch-input: draws the focus outline itself on keyboard focus.

In forced-colours mode these states keep a visible system colour: switch-input (border), switch-input:checked (fill), switch-thumb (mark).

Pattern: WAI-ARIA Authoring Practices.

Keyboard

KeysAction
TabMoves focus to the switch.
SpaceTurns it on or off.

Source: a native <input type="checkbox" role="switch"> (switch.client.tsx), which adds no key handling.

Figma

Node ids from design/component-map.json, which nz gen writes from component.json. The links open the Nizivo Figma library, which may ask you to sign in.

On this page