Switch
Switch turns a single setting on or off, and the change takes effect straight away. Use it for preferences and settings.
Beta until design approves the darker off track (code-only, follows C48; Figma's Soft-200 is 1.19:1, C20) and the focus indicator (C5) is resolved. Figma has the switch only as a remote component inside Dropdown Items; there is no local standalone switch.
Preview
Change the controls to try every supported combination. The switch is controlled here, so the code follows each click.
A short nudge at 7 pm to keep your streak going.
const [checked, setChecked] = useState(true)
<Switch
label="Daily study reminder"
description="A short nudge at 7 pm to keep your streak going."
checked={checked}
onCheckedChange={setChecked}
/>Installation
Availability
@nuton/ui and @nuton/tokens are private workspace packages and aren't published yet (D4, D12). Inside the Nuton monorepo, add them as workspace dependencies.
pnpm add @nuton/ui @nuton/tokensnpm install @nuton/ui @nuton/tokensyarn add @nuton/ui @nuton/tokensimport '@nuton/tokens/tokens.css'
import '@nuton/ui/styles.css'Usage
import { Switch } from '@nuton/ui'
<Switch
label="Daily reminders"
description="A notification when you haven't studied today."
defaultChecked
onCheckedChange={(on) => savePreference('reminders', on)}
/>- Use a switch when the change applies immediately, with no Save button. Inside a form that is submitted, use a Checkbox.
- It's a native
<input type="checkbox" role="switch">: screen readers say “switch, on” or “off”, andname,valueand forms work as usual. - Name the setting, not the action: “Daily reminders”, not “Turn on daily reminders”. Don't change the label when the state changes.
- Use
flipin settings lists so switches line up at the trailing edge. - Give it a
label, wrap it in a Field, or passaria-label.
Variants and sizes
Switch has one size (Figma 32 × 20). The variants are layout options for the label.
Label layouts
Downloads your next three lessons on Wi-Fi.
<Switch aria-label="Dark mode" />
<Switch label="Sound effects" />
<Switch label="Offline lessons" description="Downloads your next three lessons on Wi-Fi." />
<Switch label="Focus mode" badge={<Badge size="sm" color="blue" appearance="light">New</Badge>} flip />| Part | Measurement |
|---|---|
| Control frame | 32 × 20 |
| Track | 28 × 16 pill, 2px inset |
| Thumb | 12 × 12, 2px from the track edge, toggle-switch shadow |
| Hit area | 32 × 24 (the invisible native input), plus the label |
| Label layout | Gap 8; label Label/Small; sublabel and description Paragraph/X Small (same as Checkbox) |
States and interactions
State tokens
Set on .nu-switch.
| Token | Value | Used for |
|---|---|---|
--nu-switch-bg | State/Faded/Base | Off track |
--nu-switch-bg-hover | Icon/Sub-600 | Off track, hover |
--nu-switch-bg-checked | State/Primary/Base | On track |
--nu-switch-bg-checked-hover | Foundation blue-700 | On track, hover (C36) |
--nu-switch-bg-invalid | State/Error/Base | Off track in error |
--nu-switch-bg-disabled · --nu-switch-ring-disabled | Bg/White · Stroke/Soft-200 | Disabled track |
--nu-switch-thumb · --nu-switch-thumb-disabled | Bg/White · Bg/Soft-200 | Thumb |
--nu-switch-focus-shadow | buttons/primary-focus | Focus halo (C5) |
Differences from Figma (pending a decision)
- Off track: Figma uses Bg/Soft-200, 1.19:1 against white (C20). A control boundary needs 3:1 (WCAG 1.4.11), so code uses State/Faded/Base (4.23:1), the same fix as checkbox frames (C48). Approved by the owner on 2026-10-14 (C54); the toggle inside menus uses it too. Off hover steps darker to Icon/Sub-600 instead of Figma's Sub-300.
- The dropdown menu's switch indicator still uses Figma's Soft-200. Align it if this change is approved.
Composition examples
Settings list
Each change saves straight away and is confirmed in a status message. Switches sit at the trailing edge with flip.
Inside a Field
A Field gives the switch its label, hint and error, and passes disabled and the error state down.
API reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | ReactNode | — | Visible label, a native <label>; clicking it toggles the switch. |
sublabel | ReactNode | — | Secondary text after the label, e.g. "(Beta)". Part of the accessible name. |
description | ReactNode | — | A second line under the label, linked with aria-describedby. |
badge | ReactNode | — | A badge after the label. Not part of the accessible name. |
flip | boolean | false | Puts the switch after the text, at the trailing edge. |
checked · defaultChecked | boolean | — | Controlled or uncontrolled on/off state. |
onCheckedChange | (checked: boolean) => void | — | Called with the new state. onChange still fires with the native event. |
disabled | boolean | false | Disables the switch and dims the label. Inside a Field, this comes from the Field. |
invalid | boolean | — | Marks the switch invalid (aria-invalid, error track). Inside a Field, this comes from error. |
className | string | — | Class for the outer element: the label layout when label is set, otherwise the control. |
…input props | InputHTMLAttributes | — | name, value, required, id, aria-label and other attributes go to the native input. The ref points at the input. |
Accessibility
Keyboard
| Key | Behaviour |
|---|---|
| Tab | Moves focus to the switch |
| Space | Turns the switch on or off |
Screen readers
A native checkbox with role="switch", announced as “switch, on” or “off”, named by the label and sublabel and described by the description. The badge isn't part of the name.
Focus
Focus stays on the native input; the track shows the primary focus halo (C5).
Contrast and colour
Off track 4.23:1 and on track 5.59:1 against white. On and off also differ by the thumb position, so the state never relies on colour alone. Label 17.93:1, description 6.69:1.
Touch and pointer
The control's hit area is 32 × 24 (WCAG 2.5.8) and the label is also a target.
You must: name every switch, apply the change straight away, and confirm saved changes with a status message or visible result.
Figma mapping
| Figma property | Figma values | Code |
|---|---|---|
| Active | Off · On | checked / defaultChecked |
| State | Default · Hover · Disabled | Interactive states and disabled |
| (none) | — | Focus, error and the label layout are code-only |
Guidelines and related components
Use Switch for
- Settings and preferences that apply immediately
- Turning a single feature on or off
Don't use Switch for
- Choices saved with a Submit button (use Checkbox)
- Choosing between two named options (use Radio or Button group)
- Agreeing to terms (use Checkbox)
Do and don't
Saved automatically.
Press Save to apply.