Toggle
A button that stays pressed or not.
Left out of Content first Readers need sections, navigation and little else. Toggles format text in a toolbar, and Content first avoids screens with many actions. Use instead: Button
See it live
npm run storybookWhen to use it
- Use it when: Turning a mode or format on and off in a toolbar, such as bold.
- Not when: A setting saved at once (switch), or a one-off action (button).
Instead:
- Switch: A setting.
- Button: A one-off action.
- Toggle group: Several toggles together.
Variants
What each variant is for in any design system, then what Content first decided and why. Each sample is the live story with that variant set.
defaultvariantNot decided yetWhat it is for
No border; the pressed state shows as a fill.
In Content first
Not decided yet.
outlinevariantNot decided yetWhat it is for
A border, so the toggle reads as a control at rest.
In Content first
Not decided yet.
defaultsizeNot decided yetWhat it is for
The normal size.
In Content first
Not decided yet.
smsizeNot decided yetWhat it is for
A smaller toggle.
In Content first
Not decided yet.
lgsizeNot decided yetWhat it is for
A larger toggle.
In Content first
Not decided yet.
Words
- Write to one person: "you", not "users".
- Short sentences with room to breathe.
- Explain why before asking for anything.
- Use: Read, Save for later, You, Next issue. Avoid: Click here, Submit, Users, Content.
The labels components use, from the voice tokens:
content.action.commit: Savecontent.action.cancel: Not nowcontent.action.destroy: Removecontent.action.retry: Try againcontent.action.empty-action: Browse guides
See Voice and tone for the whole voice.
Accessibility and keyboard
| Keyboard | What happens | Not |
|---|---|---|
| undefined | Space or Enter presses it. | undefined |
Test before you ship:
- It says whether it is pressed. undefined
Use it in code
npx open-ds add toggle
The component reads only component keys and semantic tokens, so it follows the brand and mode on <html>.
Tokens it reads
Toggle reads 24 tokens of its own, each an alias of a semantic token. Each row is one part: its own token, the semantic it aliases, and the value it ends at. Change a semantic and every component that reads it follows; override one of Toggle's tokens to change Toggle alone.
Content first decides what changes when you switch theme. Here a switch changes colors only, so the marked rows differ between light and dark; everything else holds steady.
| Part | Its token and the semantic it aliases | Value |
|---|---|---|
| Toggle | ||
| Gap | component.toggle.gapspace.gap.defaultvar(--toggle-gap) | space.16:1rem |
| Corner | component.toggle.radiusradius.controlvar(--toggle-radius) | radius.8:0.5rem |
| Text size | component.toggle.font-sizetype.body.font-sizevar(--toggle-font-size) | font.size.18:1.125rem |
| Weight | component.toggle.font-weighttype.label.font-weightvar(--toggle-font-weight) | font.weight.600:600 |
| Background hover Changes with theme on hover | component.toggle.background-hovercolor.surface.sunkenvar(--toggle-background-hover) | Lightstone.light.100:#F6F2EADarkstone.dark.100:#2E2A24 |
| Label hover Changes with theme on hover | component.toggle.label-hovercolor.text.mutedvar(--toggle-label-hover) | Lightstone.light.600:#61594DDarkstone.dark.400:#A39A8B |
| Border focus Changes with theme on focus | component.toggle.border-focuscolor.border.focusvar(--toggle-border-focus) | Lightnavy.light.600:#1E3A5FDarknavy.dark.600:#8FA6C4 |
| Disabled opacity disabled when disabled | component.toggle.disabled-opacity-disabledopacity.disabledvar(--toggle-disabled-opacity-disabled) | opacity.40:0.4 |
| Border invalid Changes with theme when invalid | component.toggle.border-invalidcolor.status.dangervar(--toggle-border-invalid) | Lightred.light.600:#C42B2BDarkred.dark.600:#F28B8B |
| Focus ring invalid Changes with theme when invalid | component.toggle.focus-ring-invalidcolor.status.dangervar(--toggle-focus-ring-invalid) | Lightred.light.600:#C42B2BDarkred.dark.600:#F28B8B |
| Background on Changes with theme when on | component.toggle.background-oncolor.surface.sunkenvar(--toggle-background-on) | Lightstone.light.100:#F6F2EADarkstone.dark.100:#2E2A24 |
| Label on Changes with theme when on | component.toggle.label-oncolor.text.primaryvar(--toggle-label-on) | Lightstone.light.900:#1F1B16Darkstone.dark.900:#FFFDF8 |
| Icon size | component.toggle.icon-sizesize.iconvar(--toggle-icon-size) | size.16:1rem |
| Focus on focus | component.toggle.focusborder-width.focusvar(--toggle-focus) | border-width.2:2px |
| Focus ring focus Changes with theme on focus | component.toggle.focus-ring-focuscolor.border.focusvar(--toggle-focus-ring-focus) | Lightnavy.light.600:#1E3A5FDarknavy.dark.600:#8FA6C4 |
| Focus ring offset focus Changes with theme on focus | component.toggle.focus-ring-offset-focuscolor.surface.canvasvar(--toggle-focus-ring-offset-focus) | Lightstone.light.50:#FFFDF8Darkstone.dark.0:#14110D |
| Outline | ||
| Border Changes with theme | component.toggle.outline.bordercolor.border.strongvar(--toggle-outline-border) | Lightstone.light.500:#7A7062Darkstone.dark.400:#A39A8B |
| Shadow | component.toggle.outline.shadowelevation.cardvar(--toggle-outline-shadow) | shadow.none |
| Background hover Changes with theme on hover | component.toggle.outline.background-hovercolor.surface.sunkenvar(--toggle-outline-background-hover) | Lightstone.light.100:#F6F2EADarkstone.dark.100:#2E2A24 |
| Label hover Changes with theme on hover | component.toggle.outline.label-hovercolor.text.primaryvar(--toggle-outline-label-hover) | Lightstone.light.900:#1F1B16Darkstone.dark.900:#FFFDF8 |
| Default | ||
| Padding, left and right | component.toggle.default.padding-xcomponent-spacing-map.x2var(--toggle-default-padding-x) | space.8:0.5rem |
| Sm | ||
| Height | component.toggle.sm.heightsize.control.defaultvar(--toggle-sm-height) | size.48:3rem |
| Padding, left and right | component.toggle.sm.padding-xcomponent-spacing-map.x2var(--toggle-sm-padding-x) | space.8:0.5rem |
| Lg | ||
| Padding, left and right | component.toggle.lg.padding-xcomponent-spacing-map.x3var(--toggle-lg-padding-x) | space.20:1.25rem |