Skip to content

Now in the official shadcn registry directory.

Start free

Toggle

A button that toggles between pressed and unpressed - the pressed state maps to the accent token.

formactions
A free styled version is available

Installation

Run the following command

npx shadcn@latest add @ai2/toggle

Dependencies, the @ai2/tokens theme and the component file are installed together.

Usage

TS
import { Bold } from "lucide-react"

import { Toggle } from "@/components/ui/toggle"

<Toggle aria-label="Toggle bold">
  <Bold />
</Toggle>

Icon-only toggles need an aria-label. For a set of related toggles, use Toggle Group instead.

Examples

Variants

Sizes

Tones

tone colors the pressed state: neutral uses the accent token, brand uses the brand-soft token.

With text and states

defaultPressed starts the toggle in its pressed state; pair pressed with onPressedChange for controlled usage.

Props

Toggle also accepts every radix Toggle prop - pressed, defaultPressed and onPressedChange included, plus native <button> props.

PropTypeDefaultDescription
variant"default" | "outline""default"Visual style: transparent by default, or with an input border and shadow.
size"sm" | "md" | "lg""md"Height, minimum width and padding.
tone"neutral" | "brand""neutral"Pressed-state color: neutral maps to the accent token, brand to the brand-soft token.

ai2 Toggle: a pressed-state button for React toolbars

The ai2 Toggle is a shadcn-compatible toggle button for React, built on the radix-ui Toggle primitive and styled with Tailwind CSS v4. It is a two-state button for on and off controls like Bold in a text editor, grid versus list in a file browser, or mute in a call bar. The pressed state maps to the accent token, so the on state follows your theme in both light and dark mode.

Because it ships through the shadcn registry format, you install it with one CLI command, an MCP agent, or a copy-paste, and the source lands in your own project. You own the file; there is no runtime dependency on ai2 itself. The live example above is the exact component you get.

What is the ai2 Toggle?

It is a single Toggle component with three style axes defined in a cva matrix: variant (default transparent, or outline with an input border and shadow) and size (sm, md, lg) and tone (neutral for an accent pressed state, brand for a brand-soft one). The anatomy matches shadcn/ui, so existing snippets and AI agents keep working without changes.

State is handled by the radix primitive: defaultPressed for uncontrolled usage, or pressed with onPressedChange when React state owns the value. The pressed visual reads from data-[state=on], styled with the accent token.

Why use it

  • Accessible by construction: The radix-ui Toggle primitive renders a real button with aria-pressed, so screen readers announce on and off correctly without any extra wiring.
  • Correct semantics for on/off: A toggle button is the right pattern when a control switches a mode in place, unlike a Checkbox (form input) or a Switch (settings on/off with immediate effect).
  • Two variants, three sizes, two tones: default stays transparent until hovered or pressed; outline carries an input border for toolbar rows. sm, md and lg cover dense toolbars to touch targets, and the brand tone recolors the pressed state.
  • Icon-ready sizing: Minimum widths per size keep icon-only toggles square, and unsized SVG children are normalized to size-4 automatically.
  • Agent-readable metadata: The registry item describes the variant and size axes and intended use in plain words, so an MCP agent can find, inspect and install it without guessing.

Features

  • shadcn registry install: One command adds the component, its dependencies and the @ai2/tokens theme to your project.
  • Controlled and uncontrolled state: Use defaultPressed for simple cases or pair pressed with onPressedChange when other UI depends on the state.
  • Token-driven pressed state: data-[state=on] maps to the accent background and foreground by default; tone="brand" swaps it for the brand-soft tokens, so the on state recolors with your theme instead of a hardcoded gray.
  • Focus-visible ring: A 3px ring appears on keyboard focus only, driven by the shared ring token.
  • Motion from tokens: The color transition reads --motion-fast from the shared token file, matching every other ai2 component.
  • Reusable toggleVariants export: The cva matrix is exported as toggleVariants, which is exactly what Toggle Group imports to keep group items visually identical.

Production tips

  • Label icon-only toggles: An icon-only toggle has no accessible name. Always set aria-label, like aria-label="Toggle bold", so screen readers announce what is being switched.
  • Do not use it as a Switch: For settings that read as on/off in a list, use the ai2 Switch. Reserve Toggle for in-context mode buttons like formatting controls.
  • Reach for Toggle Group for sets: Alignment pickers and view switchers are selection problems. Toggle Group handles single or multiple selection and keyboard focus across the set.
  • Keep the pressed state obvious: The accent background marks the on state. If you override colors, keep enough contrast between on and off; a toggle whose states look alike is worse than a plain button.
  • Prefer outline in crowded toolbars: On busy surfaces the default transparent variant can disappear. The outline variant keeps each control visible before interaction.

Works with the rest of ai2

The toggle is a toolbar citizen. Group related controls with the ai2 Toggle Group (which reuses this component's variants), separate clusters with an ai2 Separator, and explain icon-only controls with an ai2 Tooltip.

For one-shot actions next to your toggles, use the ai2 Button; for boolean settings in a form, the ai2 Switch is the better semantic fit. Everything shares one token source, so combinations stay visually consistent in both modes.

FAQs

Get new components in your inbox

Component drops, new themes and release notes. No spam, and you can unsubscribe from any email.

© 2026 ai2 design system · MIT licensed · Built with its own components