Skip to main content

Switch

Accessible toggle / switch component used to represent a boolean on/off state. Supports keyboard interaction, ARIA switch semantics, and both controlled and uncontrolled usage.


Usage

Basic usage (uncontrolled)

import { Switch } from '@nofinite/nui';

<Switch label="Enable notifications" defaultChecked />;

Controlled usage

const [on, setOn] = React.useState(false);

<Switch checked={on} onChange={setOn} label="Use beta features" />;

Variants

This component does not support visual variants.

Visual state is derived from:

  • checked / defaultChecked
  • disabled

Styling is handled via CSS variables and [data-state] attributes.


Sizes

The Switch has a fixed size by design to preserve accessibility and hit-target consistency.

If you need size changes, create a wrapper or custom CSS variant instead of resizing arbitrarily.


States

<Switch defaultChecked />
<Switch disabled />
<Switch checked={true} disabled />

Supported states

  • On / Off

    • Driven by checked (controlled) or defaultChecked (uncontrolled)
  • Disabled

    • Blocks mouse and keyboard interaction
    • Removes focusability
    • Applies reduced opacity

Native Props / Composition

The Switch is composed of:

  • A semantic <button>
  • role="switch"
  • aria-checked for state
  • Optional hidden <input> for form integration
<Switch
id="notifications"
name="notifications"
value="enabled"
aria-label="Enable notifications"
className="my-custom-switch"
/>

You can safely pass:

  • id
  • name
  • value
  • className

Props

PropTypeDefaultDescription
checkedbooleanControlled checked state
defaultCheckedbooleanfalseInitial state for uncontrolled usage
onChange(checked: boolean) => voidCalled when state changes
disabledbooleanfalseDisables interaction and focus
labelReact.ReactNodeOptional visible label text or element
idstringautoID for the switch control
namestringEnables form submission via hidden input
valuestring"on" / "off"Value submitted when used in a form
classNamestring""Additional class names for the root element

Behavior Notes

  • Works in controlled and uncontrolled modes.

  • Spacebar toggles the switch when focused.

  • Click restores focus to the control automatically.

  • When used inside a form:

    • A hidden input is rendered.
    • Value is submitted only when the switch is on.
<form>
<Switch name="subscribe" defaultChecked value="subscribed" />
</form>

Accessibility

  • Renders as a <button> with role="switch"

  • Uses aria-checked to expose state

  • Keyboard support:

    • Tab → focus
    • Space → toggle
  • Disabled state:

    • aria-disabled="true"
    • Removed from tab order
  • Label is programmatically associated via wrapping <label>

Example for icon-only usage:

<Switch aria-label="Enable dark mode" />

Layout

  • Inline-flex layout by default
  • Switch and label are horizontally aligned
  • Does not stretch to fill width
<Switch label="Full row" style={{ marginTop: 16 }} />

Best Practices

Do

  • Use for binary on/off settings
  • Prefer controlled mode when state matters globally
  • Always provide a visible label or aria-label
  • Use inside forms when persistence is needed

Don’t

  • Use as a replacement for checkboxes with multiple selections
  • Resize arbitrarily (breaks touch targets)
  • Rely on color alone to convey state
  • Nest interactive elements inside the label