Switch

Switch turns a single setting on or off, and the change takes effect straight away. Use it for preferences and settings.

  • Beta
  • Accessibility
  • Figma Switch [1.1] 57:15314 (remote, in Dropdown Items)
  • packages/ui/src/components/Switch

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.

tsx
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.

bash
pnpm add @nuton/ui @nuton/tokens
tsx
import '@nuton/tokens/tokens.css'
import '@nuton/ui/styles.css'

Usage

tsx
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”, and name, value and 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 flip in settings lists so switches line up at the trailing edge.
  • Give it a label, wrap it in a Field, or pass aria-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.

New
PartMeasurement
Control frame32 × 20
Track28 × 16 pill, 2px inset
Thumb12 × 12, 2px from the track edge, toggle-switch shadow
Hit area32 × 24 (the invisible native input), plus the label
Label layoutGap 8; label Label/Small; sublabel and description Paragraph/X Small (same as Checkbox)

States and interactions

OffState/Faded/Base track (code-only, 4.23:1), white thumb at the start.
OnState/Primary/Base track (C20), thumb at the end.
HoverOff: Icon/Sub-600. On: Foundation blue-700. Only on hover-capable pointers; the label counts.
Focus (code-only)Figma has no focused switch. Code adds the primary focus halo, below 3:1 today (C5).
DisabledWhite track with a Soft-200 ring and a Soft-200 thumb, on or off. Label Disabled-500.
Error (code-only)Figma has none. The off track turns State/Error/Base (C6); pair it with an error message.

State tokens

Set on .nu-switch.

TokenValueUsed for
--nu-switch-bgState/Faded/BaseOff track
--nu-switch-bg-hoverIcon/Sub-600Off track, hover
--nu-switch-bg-checkedState/Primary/BaseOn track
--nu-switch-bg-checked-hoverFoundation blue-700On track, hover (C36)
--nu-switch-bg-invalidState/Error/BaseOff track in error
--nu-switch-bg-disabled · --nu-switch-ring-disabledBg/White · Stroke/Soft-200Disabled track
--nu-switch-thumb · --nu-switch-thumb-disabledBg/White · Bg/Soft-200Thumb
--nu-switch-focus-shadowbuttons/primary-focusFocus 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.

  • A notification when you haven’t studied today.

  • Plays a sound when you finish a lesson.

  • Downloads your next three lessons on Wi-Fi.

Inside a Field

A Field gives the switch its label, hint and error, and passes disabled and the error state down.

Your teacher sees completed lessons and quiz scores, not your notes.

Sharing is off.

API reference

Props

Switch props
PropTypeDefaultDescription
labelReactNode—Visible label, a native <label>; clicking it toggles the switch.
sublabelReactNode—Secondary text after the label, e.g. "(Beta)". Part of the accessible name.
descriptionReactNode—A second line under the label, linked with aria-describedby.
badgeReactNode—A badge after the label. Not part of the accessible name.
flipbooleanfalsePuts the switch after the text, at the trailing edge.
checked · defaultCheckedboolean—Controlled or uncontrolled on/off state.
onCheckedChange(checked: boolean) => void—Called with the new state. onChange still fires with the native event.
disabledbooleanfalseDisables the switch and dims the label. Inside a Field, this comes from the Field.
invalidboolean—Marks the switch invalid (aria-invalid, error track). Inside a Field, this comes from error.
classNamestring—Class for the outer element: the label layout when label is set, otherwise the control.
…input propsInputHTMLAttributes—name, value, required, id, aria-label and other attributes go to the native input. The ref points at the input.

Accessibility

Keyboard

KeyBehaviour
TabMoves focus to the switch
SpaceTurns 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 propertyFigma valuesCode
ActiveOff · Onchecked / defaultChecked
StateDefault · Hover · DisabledInteractive 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

DoName the setting The switch already says on or off; the label says what is on.
Don'tChange the label with the state “Reminders are on” plus “switch, on” is read twice, and the label jumps when toggled.

Saved automatically.

DoApply the change immediately People expect a switch to act like a light switch.

Press Save to apply.

Don'tMake people press Save after a switch Use a Checkbox in forms that are submitted.