Components

Toggle

A two-state button that can be turned on or off — ideal for icon controls in toolbars and inline formatting actions.

Basic usage

Wrap a Lucide icon and provide an aria-label. Click to flip between on and off. Icons without an explicit size class are set to 16px by the toggle's own base styles.

Variants

Use default for toolbar groups and outline for standalone controls that need a visible boundary. Both share the same pressed treatment — bg-accent with text-accent-foreground.

Sizes

Three sizes — sm (32px), default (36px), and lg (40px) — to match the density of the surrounding UI. Each one also sets a matching minimum width, so an icon-only toggle stays square.

States

Start a toggle in the on position with defaultPressed, or block interaction with disabled. Toggles can pair an icon with a text label.

The toggleVariants helper

The cva recipe behind the component is exported as toggleVariants from @comitor/ui. Call it to give any element the toggle's shape and state styling — an editor plugin's own button, a link, a menu item — and merge extra classes with cn. It is the same recipe ToggleGroupItem uses. Borrowing the styles means owning the semantics: set aria-pressed and the data-state attribute the pressed styles key off yourself.

Props

PropTypeDefaultDescription
variant'default' | 'outline''default'Visual style — transparent by default, or bordered with a shadow for standalone controls.
size'default' | 'sm' | 'lg''default'Height, padding and minimum width: sm is 32px, default 36px, lg 40px.
pressedbooleanControlled on/off state. Pair with onPressedChange.
defaultPressedbooleanfalseInitial pressed state when uncontrolled.
onPressedChange(pressed: boolean) => voidFires when the pressed state changes.
disabledbooleanfalseRemoves pointer events and reduces opacity to 50%.
aria-invalidbooleanTints the focus ring and switches the border to border-destructive-ink for failed validation.
classNamestringAdditional Tailwind classes to merge.
...restRadix Toggle.Root propsEverything else is forwarded to the underlying button.

Accessibility

  • Built on Radix Toggle, which exposes the on/off state to assistive tech via aria-pressed.
  • Always pass an aria-label for icon-only toggles so the control has an accessible name.
  • Fully keyboard operable — focus with Tab and flip with Enter or Space.
  • A focus-visible ring using the brand gold ring token appears on keyboard navigation and stays hidden on click.
  • The disabled state removes pointer events and is conveyed to the accessibility tree.
  • Pressed state is carried by a real background change (bg-accent), not by colour alone on the icon, so it survives both palettes and both themes.