Toggle
Stays pressed until it's pressed again, like Bold in a text editor.
Installation
The CLI installs the Radix or Base UI file to match your project.
If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.
When to use
Use it
- For a button that stays pressed until it's pressed again, like Bold in a text editor.
- For an icon button that shows or hides part of a view, like a list view's charts or filters, beside buttons that don't stay pressed.
- For a labelled button that marks something, like Favorite.
- In place of Lightning's stateful button icon, or a stateful button whose label stays the same.
Don't use it
- A setting turns on or off in a form or settings list. Use Switch or Checkbox.
- People pick one of a few related options, like text alignment. Use Toggle Group.
- The button runs an action and doesn't stay pressed. Use Button.
- The label changes to name the next action, such as Follow becoming Unfollow. Use Button.
Usage
An icon-only toggle takes an aria-label, which also gives it the square icon padding. A toggle with text is named by its text and pads like a button, as the Text example shows.
import { BoldIcon } from "lucide-react"
import { Toggle } from "@/components/ui/toggle"<Toggle aria-label="Bold" variant="outline">
<BoldIcon />
</Toggle>Examples
Bare
Icon toggles with no border, the `default` variant, as in a note's formatting toolbar, Bold pressed.
Text
Toggles with labels: one off, one pressed, and a bare text toggle.
Sizes
Small, default and large, set with `size` on `Toggle`.
Disabled
Disabled toggles, pressed and not, in both variants.
API reference
Toggle
| Prop | Type | Default |
|---|---|---|
variant | "default" | "outline" | "default" |
size | "default" | "sm" | "lg" | "default" |
Also takes every Radix Toggle.Root (opens in a new tab) prop.
SLDS mapping
Toggle is SLDS's stateful icon button, and a toggle with text is its dual-stateful button (slds-button_dual-stateful).
Known gaps:
- A bare (
variant="default") toggle with text pads like a button. SLDS's base stateful button has no padding; ours keeps it so the pressed fill has room.
| Prop | Value | SLDS | Notes |
|---|---|---|---|
variant | default | slds-button_icon-container | Bare. Pressed is slds-is-selected: a brand fill. |
variant | outline | slds-button_icon-border-filled | Bordered. Pressed is slds-is-selected. With text it's slds-button_neutral slds-button_dual-stateful. |
size | default | slds-button_icon-container | Button's default height. |
size | sm | none | Button's small height. SLDS's small icon button is smaller. |
size | lg | none | Button's large height. |
Accessibility
- Name an icon-only toggle with
aria-label. Keep both the visible label and the name the same when it's pressed;aria-pressedcarries the state. - A disabled toggle can't take focus or show a tooltip. Say why in nearby text.
Motion
- In Cosmos, hovering lifts an
outlinetoggle 1.5px and a pressed toggle 2px, each with an edge shadow, over 150ms. Lightning Blue sets the lift and the shadow to none. - The lift runs with reduced motion too.
Responsive behavior
- It keeps its height and doesn't shrink in a flex row, and text doesn't wrap. Let a toolbar wrap with
flex-wrap.
Rules
- Don't add
aria-labelto a toggle with visible text: it gets icon padding, and the label replaces the text as the name. - Show the pressed state with
defaultPressedorpressed, never with a class. The state has to reacharia-pressed. - Never override colors, radius or height with utility classes. The tokens carry each theme.