Summit
ComponentsActions

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 outline Toggle 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

ElementUsage
Label*Optional
ContainerRequired
Icon*Optional
Focus outlineKeyboard focus only
Pressed markPressed state only

* A Toggle has a label, an icon, or both.

Variants

VariantPurpose
defaultAn icon-only Toggle in a toolbar or on a record, such as “Bold” or “Favorite”
outlineA 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.

ContentPressed Mark
An icon of an object, like a starThe fill weight
A glyph, like B or IThe bold weight
A label with no iconA leading check

See Elevation for the rule and Iconography for the two weights.

DoAdd a check before the label of a pressed Toggle.
Don’tWhen the tint is the only mark, users can’t tell an active filter from one under the pointer because hover uses the same fill.

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

StringRuleExampleCounterexample
LabelName what is on, and keep the same words in both states“Overdue”“Show overdue”, then “Hide overdue”
aria-labelName 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/toggle

Usage

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.

Mark the Pressed State
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".

With a Label
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

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

On this page