Skip to main content

Toggle

A button that stays pressed or not.

In Accessible first

See it live​

Start Storybook to see it live: npm run storybook

When to use it​

In Accessible first: Turning a mode on and off, with a word on the button. Not a form answer or a one-off action.

  • 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:

Variants​

What each variant is for in any design system, then what Accessible first decided and why. Each sample is the live story with that variant set.

defaultvariantNot used in Accessible first
Start Storybook to see it live

What it is for

No border; the pressed state shows as a fill.

✓Toolbars where toggles sit together.
✕A toggle alone on a busy background.

In Accessible first

Every action looks like a control people can find, so the toggle keeps its border.

outlinevariantUsed in Accessible first
Start Storybook to see it live

What it is for

A border, so the toggle reads as a control at rest.

✓A toggle that stands alone.
✕A dense toolbar of many toggles.

In Accessible first

Every toggle, with a strong border and a word, so it reads as a control at any zoom.

defaultsizeUsed in Accessible first
Start Storybook to see it live

What it is for

The normal size.

✓Most toolbars.
✕Very dense toolbars.

In Accessible first

Every toggle. Large targets help people with motor needs.

smsizeNot used in Accessible first
Start Storybook to see it live

What it is for

A smaller toggle.

✓Dense toolbars and compact panels.
✕Touch screens.

In Accessible first

Large targets help people with motor needs; nothing smaller.

lgsizeNot used in Accessible first
Start Storybook to see it live

What it is for

A larger toggle.

✓A few toggles that need to be easy to hit.
✕Dense toolbars.

In Accessible first

The default size is already large for motor needs; a bigger one adds nothing.

Why it works this way​

Toggle looks the way it does because of 4 answers about this product. Each card is one answer, in three steps: the answer, what it decided for Toggle, and what would move if it changed.

How do people recall the interface?human.q2
1The answer
They see it fresh each time

Nobody remembers the interface from last time.

2So Toggle
  • –does not use default: Every action looks like a control people can find, so the toggle keeps its border.
It also shapes Button: secondary Button: ghost Button: disabled Field: responsive
3If it changed
2
Toggle decisions would reopen

and 1 answer that follow from it: Actions and status.

What separates groups on the page?elevation.definition
1The answer
Lines

Strong borders separate groups at any zoom.

2So Toggle
  • –does not use default: Every action looks like a control people can find, so the toggle keeps its border.
  • ✓uses outline: Every toggle, with a strong border and a word, so it reads as a control at any zoom.
It also shapes Item: default Item: outline
3If it changed
2
Toggle decisions would reopen

No other answer follows from it.

What do icons do?iconography.roles
1The answer
Actions and status

Icons support words; they never replace them.

2So Toggle
  • ✓uses outline: Every toggle, with a strong border and a word, so it reads as a control at any zoom.
It also shapes Button: icon Input group: inline-end
3If it changed
1
Toggle decision would reopen

No other answer follows from it.

What is the smallest target?accessibility.values
1The answer
Large

Large targets for tremor and touch.

2So Toggle
  • ✓uses default: Every toggle. Large targets help people with motor needs.
  • –does not use sm: Large targets help people with motor needs; nothing smaller.
  • –does not use lg: The default size is already large for motor needs; a bigger one adds nothing.
It also shapes Button: default Button: compact Button: large Item: default Item: sm
3If it changed
3
Toggle decisions would reopen

No other answer follows from it.

Words​

  • Use common words. Explain any term you must use.
  • One idea per sentence. Put the action first.
  • Never blame the person.
  • Use: Continue, Change, Start, You. Avoid: Invalid, Utilise, Submit, Error code.

The labels components use, from the voice tokens:

  • content.action.commit: Continue
  • content.action.cancel: Go back
  • content.action.destroy: Delete
  • content.action.retry: Try again
  • content.action.empty-action: Start a new application

See Voice and tone for the whole voice.

Accessibility and keyboard​

KeyboardWhat happensNot
undefinedSpace 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.

Changes with theme

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

PartIts token and the semantic it aliasesValue
Toggle
Gapcomponent.toggle.gapspace.gap.defaultvar(--toggle-gap)space.16:1rem
Cornercomponent.toggle.radiusradius.controlvar(--toggle-radius)radius.6:0.375rem
Text sizecomponent.toggle.font-sizetype.body.font-sizevar(--toggle-font-size)font.size.19:1.1875rem
Weightcomponent.toggle.font-weighttype.label.font-weightvar(--toggle-font-weight)font.weight.700:700
Background hover
Changes with theme
on hover
component.toggle.background-hovercolor.surface.sunkenvar(--toggle-background-hover)Lightgray.light.100:#EDEDEDDarkgray.dark.100:#222222
Label hover
Changes with theme
on hover
component.toggle.label-hovercolor.text.mutedvar(--toggle-label-hover)Lightgray.light.500:#595959Darkgray.dark.500:#949494
Border focus
Changes with theme
on focus
component.toggle.border-focuscolor.border.focusvar(--toggle-border-focus)Lightblue.light.600:#0B4FC0Darkblue.dark.600:#8AB4F8
Disabled opacity disabled
when disabled
component.toggle.disabled-opacity-disabledopacity.disabledvar(--toggle-disabled-opacity-disabled)opacity.50:0.5
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)Lightgray.light.100:#EDEDEDDarkgray.dark.100:#222222
Label on
Changes with theme
when on
component.toggle.label-oncolor.text.primaryvar(--toggle-label-on)Lightgray.light.900:#141414Darkgray.dark.900:#F7F7F7
Icon sizecomponent.toggle.icon-sizesize.iconvar(--toggle-icon-size)size.20:1.25rem
Focus
on focus
component.toggle.focusborder-width.focusvar(--toggle-focus)border-width.3:3px
Focus ring focus
Changes with theme
on focus
component.toggle.focus-ring-focuscolor.border.focusvar(--toggle-focus-ring-focus)Lightblue.light.600:#0B4FC0Darkblue.dark.600:#8AB4F8
Focus ring offset focus
Changes with theme
on focus
component.toggle.focus-ring-offset-focuscolor.surface.canvasvar(--toggle-focus-ring-offset-focus)Lightgray.light.50:#F7F7F7Darkgray.dark.0:#0A0A0A
Outline
Border
Changes with theme
component.toggle.outline.bordercolor.border.strongvar(--toggle-outline-border)Lightgray.light.500:#595959Darkgray.dark.500:#949494
Shadowcomponent.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)Lightgray.light.100:#EDEDEDDarkgray.dark.100:#222222
Label hover
Changes with theme
on hover
component.toggle.outline.label-hovercolor.text.primaryvar(--toggle-outline-label-hover)Lightgray.light.900:#141414Darkgray.dark.900:#F7F7F7
Default
Padding, left and rightcomponent.toggle.default.padding-xcomponent-spacing-map.x2var(--toggle-default-padding-x)space.8:0.5rem
Sm
Heightcomponent.toggle.sm.heightsize.control.defaultvar(--toggle-sm-height)size.52:3.25rem
Padding, left and rightcomponent.toggle.sm.padding-xcomponent-spacing-map.x2var(--toggle-sm-padding-x)space.8:0.5rem
Lg
Padding, left and rightcomponent.toggle.lg.padding-xcomponent-spacing-map.x3var(--toggle-lg-padding-x)space.20:1.25rem