Toggle
A Toggle allows users to turn an option on with one click and off with the next.
When to Use
- for a format that applies immediately and turns off the same way, such as bold or italic in an editor
- to mark one record, for example as a favorite
- as an
outlineToggle with a label, for a filter that is on or off, like “Overdue”
When Not to Use
- for an action that runs once on every click (use a Button)
- for a setting in a form (use a Switch or a Checkbox)
- for a set of Toggles that users move between with the arrow keys (use a Toggle Group)
- to choose one of a few options (use a Segmented Control)
Anatomy
| Element | Usage |
|---|---|
| Label* | Optional |
| Container | Required |
| Icon* | Optional |
| Focus outline | Keyboard focus only |
| Pressed mark | Pressed state only |
* A Toggle has a label, an icon, or both.
Variants
| Variant | Purpose |
|---|---|
default | An icon-only Toggle in a toolbar or on a record, such as “Bold” or “Favorite” |
outline | A Toggle with a label, such as “Italic” or the filter “Overdue” |
Sizes
A Toggle has the sm, default, and lg sizes of a Button and the same height at each, so the two line up in a toolbar. See Sizing for where to use each height.
A Toggle has no xs size and no icon sizes.
States
A pressed Toggle has the same tint as a hovered one, so users can’t tell the state from the tint alone. Add a mark to a pressed Toggle as well.
| Content | Pressed Mark |
|---|---|
| An icon of an object, like a star | The fill weight |
| A glyph, like B or I | The bold weight |
| A label with no icon | A leading check |
See Elevation for the rule and Iconography for the two weights.
Behavior
By default, a Toggle is as wide as its content and at least as wide as it is tall. The label doesn’t wrap.
Content
| String | Rule | Example | Counterexample |
|---|---|---|---|
| Label | Name what is on, and keep the same words in both states | “Overdue” | “Show overdue”, then “Hide overdue” |
aria-label | Name the format or the mark, not the action | “Bold” | “Turn on bold” |
aria-pressed communicates the state to assistive technology. The ARIA Authoring Practices Guide asks that the label of a toggle stay the same when its state changes.
Accessibility
Base UI’s Toggle renders a native button and sets aria-pressed on it.
An icon-only Toggle has no text, so it needs an aria-label for screen readers to announce it, as
WCAG 2.2 SC 4.1.2 Name, Role, Value requires. Show the same words in a Tooltip, as an icon-only
Button does.
A pressed Toggle needs a mark in addition to its tint so that users can tell that it’s on. WCAG 2.2 SC 1.4.11 Non-text Contrast requires 3 to 1 for what identifies a state, and the tint is below that.
Installation
npx shadcn@latest add @summit/toggleUsage
import { Toggle } from '@/components/ui/toggle';
import { TextBIcon } from '@phosphor-icons/react';
<Toggle aria-label="Bold">
<TextBIcon />
</Toggle>;Mark the Pressed State
To change the icon when the Toggle is pressed, pass a function to render. The function receives the props of the button and state.pressed.
import { StarIcon } from '@phosphor-icons/react';
<Toggle
aria-label="Favorite"
render={(props, state) => (
<button type="button" {...props}>
<StarIcon weight={state.pressed ? 'fill' : 'regular'} />
</button>
)}
/>;With a Label
If the Toggle has a label, render the check only while the Toggle is pressed, and mark it with data-icon="inline-start".
import { CheckIcon } from '@phosphor-icons/react';
<Toggle
variant="outline"
render={(props, state) => (
<button type="button" {...props}>
{state.pressed && <CheckIcon data-icon="inline-start" />}
Overdue
</button>
)}
/>;API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'outline' | 'default' | outline adds an edge |
size | 'default' | 'sm' | 'lg' | 'default' | The height, the text size, and the icon size |
Other props are passed to Base UI’s Toggle. See the Base UI Toggle documentation for pressed, defaultPressed, onPressedChange, and render.