Toggle
A toggle is a switch control that lets users turn a setting on or off.
Ready to use
A toggle is a switch control that flips a single setting between two opposing states — on or off — and applies the change immediately. Reach for one when the setting is binary and takes effect the moment it is switched, the way you’d expect a physical light switch to behave. Built on a native <input type="checkbox">, it pairs a sliding thumb with a clear text label so the state reads at a glance.
Anatomy
Section titled “Anatomy”- Switch
- Label
The Switch is a single native control that renders the whole toggle: the pill-shaped track carries the on / off colour, the thumb slides from one end to the other, and an icon inside the thumb — a cross when off, a check when on — repeats the state without relying on colour. The Label names the setting the switch controls.
When to use it
Section titled “When to use it”Use a Toggle when:
- A single setting flips between two opposing states (on / off, enabled / disabled).
- The change takes effect immediately, with no separate Save or Submit step.
- The control adjusts a system or preference setting — notifications, dark mode, Wi-Fi.
Avoid a Toggle when:
- The user picks from a list of non-exclusive options — that’s a Checkbox.
- The choice only applies after submitting a form — a Checkbox reads as “pending” in a way a switch does not.
- More than two states are possible, or the action needs confirmation before it takes effect.
Properties
Section titled “Properties”Track
The pill-shaped background rendered on the native input. It carries the visible on / off state — the neutral emphasis fill when on, a muted fill when off — and mutes to a subtle fill when disabled. The change of colour is never the only cue; it always moves with the thumb.
Thumb
The circular knob that slides across the track. Its position — leading edge for off, trailing edge for on — is the primary, colour-independent signal of the state, so it survives for colour-blind users and in high-contrast modes.
Icon
Sits inside the thumb and repeats the state a third time: a cross when off, a check when on. Decorative — the on / off value is conveyed semantically by the native <input type="checkbox">, not the icon.
State
Rested, Hover, Pressed, Disabled, and Focus, plus an Error treatment via .is-error. Hover and Pressed add a soft outline around the thumb; Focus shows the global focus ring; Disabled mutes the track and drops the control from the tab order. Each state is driven by its own design-token set so it adapts across schemes.
Size
The switch itself is one fixed size, in every state and on every surface — sizing it down would put the thumb below a comfortable target. What the Small and Large variants change is the label: Large (the default, for forms and settings) sets it on the body-6 type scale, Small drops it to body-7 for dense layouts. The switch is identical in both.
Platform considerations
Section titled “Platform considerations”Desktop
Mouse and keyboard both work — the switch is a single tab stop, toggled with Space. Align the switch with its label on the leading edge and keep the pair on one line so the relationship is obvious.
Tablet
Touch and pointer both apply. Keep the label’s clickable area extended to the full row so a tap anywhere on the line flips the switch without having to hit the thumb precisely.
Mobile
Touch-first. The switch is a small target on its own, so let the label carry the rest of it — the label is wired to the input, which means a tap anywhere on the text flips the switch. Give each row enough height that the two together stay comfortable to hit. Stack toggles vertically in a settings list; never crowd two switches side by side at narrow widths.
Best practices
Section titled “Best practices”A toggle promises an instant result — make the label describe the setting, and let the switch position and icon, not colour alone, tell the state.
Do
Use a toggle only for binary settings that apply immediately. Label it with the setting it controls (“Notifications”), phrased so “on” is the affirmative. Keep the label visible and next to the switch. Let the thumb position and icon carry the state alongside colour, and show the focus ring on keyboard focus.
Don't
Don’t use a toggle when the change only takes effect after a Save step — that implies a pending state a switch doesn’t have. Don’t use one to pick among a list (that’s a Checkbox) or when only one of several options can be chosen (that’s a Radio). Don’t rely on the track colour alone to signal the state, and don’t replace the visible label with an icon-only control.
Content guidelines
Section titled “Content guidelines”Label the toggle with the setting it controls, not the action it performs — “Notifications” or “Dark mode”, never “Turn on notifications”. Phrase it so the “on” position is the affirmative, matching the switch’s meaning, and use sentence case (“Auto-play videos”). Keep the label short and self-describing; if the setting needs a caveat, put it in supporting text beneath the switch rather than lengthening the label.
A toggle is a switch control that lets users turn a setting on or off. Put tng-toggle-control on a wrapper holding a native <input type="checkbox"> and its label — wrap the input in a <label> as below, or keep them siblings inside a <div> and wire them with for / id. Everything the switch renders comes off that one input: the track is its background, and the thumb and the cross / check glyph are its ::before and ::after.
<label class="tng-toggle-control"> <input type="checkbox" /> <span>Off</span></label><label class="tng-toggle-control"> <input type="checkbox" checked /> <span>On</span></label>The switch is one fixed size. tng-toggle-control rides the body type scale, so the is-* typography modifiers resize the label only — the default is body-6, and is-7 is the smaller label Figma calls Size=Small.
<label class="tng-toggle-control"> <input type="checkbox" checked /> <span>Default label</span></label><label class="tng-toggle-control is-7"> <input type="checkbox" checked /> <span>Small label</span></label>States
Section titled “States”Disabled
Section titled “Disabled”Use the native disabled attribute. It mutes the track, sets cursor: not-allowed on the whole control, and takes the switch out of the tab order.
<label class="tng-toggle-control"> <input type="checkbox" disabled /> <span>Off and disabled</span></label><label class="tng-toggle-control"> <input type="checkbox" checked disabled /> <span>On and disabled</span></label>Indeterminate
Section titled “Indeterminate”A checkbox whose indeterminate IDL property is true parks the thumb halfway along the track. There is no HTML attribute for it — set it from script, and only where “partially on” is a state the setting really has (a parent switch over a group of sub-settings). Note that this state has no equivalent under role="switch", which admits only on and off.
document.querySelector('#sync').indeterminate = true;Add is-error to the control to recolour the label and draw the error ring around the switch. The same treatment applies on its own when the input is :invalid — a required switch the user hasn’t turned on, for instance — so constraint validation needs no extra class. Either way the treatment steps aside while the switch has focus, so the focus ring stays legible. is-error is a visual cue only; see the Accessibility tab for the aria-invalid and aria-describedby wiring that carries it to assistive technology.
The toggle follows the WAI-ARIA Switch pattern — a single control that flips a setting between on and off with immediate effect — and meets WCAG 2.1 AA. Built on a native <input type="checkbox">, an accessible toggle is reachable and operable from the keyboard, carries a label that names the setting it controls, and reports its on / off state to assistive technology — so the setting is clear whether the user is looking at it, listening to it, or tabbing through it.
For designers
Section titled “For designers”- Every state (rested, hover, pressed, disabled, focus) must maintain accessible contrast on every supported surface, in both the on and off positions. Source: WCAG 1.4.3 Contrast (Minimum).
- The on / off state must never rely on colour alone — pair the track’s colour change with the thumb’s position and the icon inside it, so the state survives for colour-blind users. Source: WCAG 1.4.1 Use of Color.
- Focus styles must stay visible, meet contrast requirements on every supported surface, and be clearly distinguishable from hover. Source: WCAG 2.4.7 Focus Visible.
- Use semantic colour tokens (e.g.
foreground/neutral/default) rather than fixed values, so the component adapts correctly across themes and surfaces.
For developers
Section titled “For developers”Build on a native <input type="checkbox"> and never recreate the control from <div> or <span> — the native element brings the role, state, and keyboard operability that assistive technology relies on, and it is what the styleguide’s CSS targets. role="switch" layers on top of that input rather than replacing it; the Switch card below weighs what it buys and what it costs. A toggle applies its change immediately, so don’t pair it with a Save step that implies the setting is pending. The whole control is a single tab stop — focus lands on the input, and the label is associated with it rather than being a stop of its own. The per-element roles, names, and states are in the Labelling elements section below.
Keyboard interaction
Section titled “Keyboard interaction”| Key | Action |
|---|---|
| Tab / Shift + Tab | Move focus to the next / previous control |
| Space | Toggle the focused switch between on and off |
The switch on its own is a small target — around 24 px tall, which is the floor rather than a comfortable margin. Its label counts as part of the same target, because clicking or tapping the text activates the switch, so keep the label visible and give the row enough height that the two together clear the minimum with room to spare. Source: WCAG 2.5.8 Target Size (Minimum).
Labelling elements
Section titled “Labelling elements”Give every element the role, name, and state assistive technology needs.
Switch
A native <input type="checkbox"> already exposes a checkable role and its on / off value, so a toggle is accessible with no ARIA at all. Adding role="switch" changes the announcement from “checked” to “on” / “off”, which matches what the control looks like and what it does; the native checked property still carries the value and the role maps it to aria-checked for you. What it costs is the indeterminate state — a switch admits only on and off, so a control that needs “partially on” has to stay a plain checkbox. Convey a non-interactive switch with the native disabled attribute, which also removes it from the tab order. Don’t move state to aria-* when the native attribute already carries it.
Label
The toggle takes its accessible name from the associated <label>, wired with for/id or by wrapping the input. Keep the label visible and self-describing, and phrase it as the setting being controlled (“Notifications”) rather than an action — never leave the name to a title or placeholder, and never replace it with an icon-only control.
Supporting and error text
The is-error class is a visual cue only, and so is the same treatment the styleguide applies on its own to an :invalid input. Pair either with aria-invalid="true" and connect the message to the input with aria-describedby, so the failure is announced after the label and conveyed to assistive technology rather than by colour alone. The error styling steps aside while the switch has keyboard focus, so the focus ring stays legible — the announced state doesn’t change with it.
Source: WCAG 4.1.2 Name, Role, Value.