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/defaultCheckeddisabled
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) ordefaultChecked(uncontrolled)
- Driven by
-
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-checkedfor 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:
idnamevalueclassName
Props
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | — | Controlled checked state |
defaultChecked | boolean | false | Initial state for uncontrolled usage |
onChange | (checked: boolean) => void | — | Called when state changes |
disabled | boolean | false | Disables interaction and focus |
label | React.ReactNode | — | Optional visible label text or element |
id | string | auto | ID for the switch control |
name | string | — | Enables form submission via hidden input |
value | string | "on" / "off" | Value submitted when used in a form |
className | string | "" | 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>withrole="switch" -
Uses
aria-checkedto expose state -
Keyboard support:
Tab→ focusSpace→ 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