Toggle
A two-state button that can be pressed on or off — bold/italic, mute, pin.
- Status
- Since
0.1.0- Accessibility pattern
- toggle button (aria-pressed)
Last updated
Install
Add Toggle from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.
pnpm dlx shadcn@latest add @vegastack/toggleUsage
import { Toggle } from "@/components/ui/toggle";
<Toggle aria-label="Toggle bold">
<Bold />
</Toggle>;Toggle is uncontrolled by default — pass defaultPressed for an initial value, or control it with
pressed + onPressedChange.
const [bold, setBold] = useState(false);
<Toggle pressed={bold} onPressedChange={setBold} aria-label="Toggle bold">
<Bold />
</Toggle>;Examples
Sizes & States
One look (no variant prop) in three sizes (sm, md, lg). Icons compose as children via
lucide-react. The toggle is a ghost at rest; when pressed it takes the system's one selected-chip
look — an evident neutral ink tint with a hairline, never a brand colour — so the "on" state reads
clearly. That look is the shared selectedChipVariants recipe, so a pressed Toggle, a pressed
ToggleGroup item, a Segmented chip and an active pill tab are the same thing by construction; a
pressed toggle also still hovers (the tint strengthens) and still presses (it drops back, previewing
the release). The states row shows off, on (defaultPressed), disabled, and disabled+on. A genuine
selection (single/multi) belongs in ToggleGroup, whose pressed items take the exact same fill.
Playground
Try the three sizes and the disabled and default-pressed states, then copy the generated JSX.
<Toggle aria-label="Toggle bold">
<Bold />
</Toggle>API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
size | "lg" | "md" | "sm" | — |
Data attributes and CSS variables on Toggle
| Attribute | Values |
|---|---|
data-size | mirrors a prop or state value |
data-slot | "toggle" |
Accessibility
- Renders a native
<button>witharia-pressedreflecting the on/off state — keyboard Enter / Space toggle it. - The pressed state is also exposed as
data-pressedfor styling; never style state withoutline: none. - The component adds no custom ring class of its own and never sets
outline: none, so keyboard focus shows the design system's global 2px:focus-visiblering (outline-ring) — keep it visible; never remove it withoutline: none. - Icon-only toggles must have an
aria-label(or visible text) so the action is announced. disabledremoves the toggle from the tab order and blocks interaction.
| Contract | States tested |
|---|---|
| Behaviour | default, disabled, error, invalid, pressed |
| Accessibility | invalid, labeled, pressed |
| Visual | default, hover, disabled, invalid, error |