Skip to content

Toggle Button

A button that stays pressed until pressed again, for turning a mode on or off, like Bold or Mute. Group several with ToggleButtonGroup for single or multiple choice.

Inputv0.1.0experimentalWCAG 2.2 AAView spec
import { ToggleButton } from "@rdloom/react";

export default function ToggleButtonBasicExample() {
  return <ToggleButton>Pin to top</ToggleButton>;
}

Installation

npx rdloom add toggle-button

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/toggle-button.json

Works, but without upgrade tracking.

Usage

import { ToggleButton } from "@rdloom/react";

<ToggleButton>Pin to top</ToggleButton>

Group multiple

import { ToggleButton, ToggleButtonGroup } from "@rdloom/react";

export default function ToggleButtonGroupMultipleExample() {
  return (
    <ToggleButtonGroup label="Text style" selectionMode="multiple" defaultSelectedKeys={["bold"]}>
      <ToggleButton id="bold">Bold</ToggleButton>
      <ToggleButton id="italic">Italic</ToggleButton>
      <ToggleButton id="underline">Underline</ToggleButton>
    </ToggleButtonGroup>
  );
}

Icon only

import { BellIcon, GlobeIcon, ImageIcon, ToggleButton, ToggleButtonGroup } from "@rdloom/react";

export default function ToggleButtonIconOnlyExample() {
  return (
    <ToggleButtonGroup label="Show in the feed" selectionMode="multiple" defaultSelectedKeys={["images"]}>
      <ToggleButton id="images" aria-label="Images">
        <ImageIcon />
      </ToggleButton>
      <ToggleButton id="links" aria-label="Links">
        <GlobeIcon />
      </ToggleButton>
      <ToggleButton id="alerts" aria-label="Alerts">
        <BellIcon />
      </ToggleButton>
    </ToggleButtonGroup>
  );
}

Outline

import { ToggleButton, ToggleButtonGroup } from "@rdloom/react";

export default function ToggleButtonOutlineExample() {
  return (
    <div className="flex flex-col items-start gap-4">
      <ToggleButton variant="outline">Mute</ToggleButton>
      <ToggleButtonGroup label="Alignment" variant="outline" defaultSelectedKeys={["left"]}>
        <ToggleButton id="left">Left</ToggleButton>
        <ToggleButton id="center">Center</ToggleButton>
        <ToggleButton id="right">Right</ToggleButton>
      </ToggleButtonGroup>
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
size

Control height, from the shared control sizes.

"sm" | "md" | "lg""md"
variant

Default is filled when pressed; outline keeps a visible border.

"default" | "outline""default"
isSelected

Controlled pressed state.

booleannone
defaultSelected

Pressed at first when uncontrolled.

booleanfalse
onChange

Called when the pressed state changes.

(isSelected: boolean) => voidnone
isDisabled

Disables the button.

booleanfalse
children

Text or an icon. An icon-only button needs an aria-label.

nodenone

Accessibility

Role button, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

  • Tab moves to the button; in a group, to the group
  • Space or Enter toggles the focused button
  • In a group, arrow keys move focus between buttons

Screen readers announce

  • Announced as a toggle button, pressed or not pressed
  • In a single-choice group, as a radio button, checked or not checked

What your code must do

  • A toggle button exposes aria-pressed (in a single-choice group, the group is a radiogroup and each button a radio)
  • The pressed state is shown by fill and weight, not only by color
  • An icon-only button has an accessible name
  • A group has an accessible name

Guidelines

Use it when

  • A mode that stays on: bold, mute, pin
  • A toolbar of formatting options, several allowed at once

Avoid it when

  • An on or off setting inside a form: use Switch or Checkbox
  • Mutually exclusive views of data: use SegmentedControl
  • A one-time action: use Button

Don't

  • Changing the label when pressed as well as the state, which reads as the opposite
  • Icon-only buttons with no accessible name

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-surface-default
  • --rd-color-surface-subtle
  • --rd-color-border-default
  • --rd-color-border-strong
  • --rd-color-action-primary
  • --rd-color-action-on-primary
  • --rd-color-text-default
  • --rd-color-focus-ring
  • --rd-radius-control