Toggle group

A row of icon or text toggles, single or multiple: one pressed fill glides between options, or each fades in on its own and neighbours join, as in a formatting toolbar.

pnpm dlx shadcn@latest add @uiarc/toggle-group
Live · keyboard ready

Our spring release is about the details people touch every day: faster search, calmer notifications, and a sidebar that remembers where you left off. Every change was tested with the teams who asked for it.

  • Formatting toolbars: bold, italic and underline as multiple, alignment as single.
  • Compact view options on a canvas, map or editor, such as grid or list, or which layers to show.
  • Any short row of icon toggles that apply immediately.
  • Use segmented-control for switching between views, ranges or tabs of content.
  • Use checkbox or switch for settings in a form that are saved together.
  • Use chip-group for filters with long text labels or many options that wrap.

Installation

Add Toggle group with the shadcn CLI, or copy the source by hand.

pnpm dlx shadcn@latest add @uiarc/toggle-group

Adds the component and its local dependencies, and installs motion. First time? Add the @uiarc registry to components.json, or use the full URL:

example.tsx
import { ToggleGroup, ToggleGroupItem } from "@/components/arc/toggle-group/toggle-group";import { AlignCenter, AlignLeft, AlignRight, Bold, Italic, Underline } from "lucide-react"; export function FormatBar() {  const [marks, setMarks] = useState<string[]>([]);  const [align, setAlign] = useState("left");  return (    <div style={{ display: "flex", gap: 8 }}>      <ToggleGroup type="multiple" label="Text style" value={marks} onValueChange={setMarks}>        <ToggleGroupItem value="bold" label="Bold"><Bold /></ToggleGroupItem>        <ToggleGroupItem value="italic" label="Italic"><Italic /></ToggleGroupItem>        <ToggleGroupItem value="underline" label="Underline"><Underline /></ToggleGroupItem>      </ToggleGroup>      <ToggleGroup label="Alignment" value={align} onValueChange={setAlign}>        <ToggleGroupItem value="left" label="Align left"><AlignLeft /></ToggleGroupItem>        <ToggleGroupItem value="center" label="Align center"><AlignCenter /></ToggleGroupItem>        <ToggleGroupItem value="right" label="Align right"><AlignRight /></ToggleGroupItem>      </ToggleGroup>    </div>  );}

API reference

2 parts. The first is the root.

ToggleGroup

A row of toggle buttons on a flat bordered strip. In single mode one tinted fill glides from option to option; in multiple mode each option's fill fades and settles in place, and neighbours that are both on join into one shape. Also exported as the default export.

PropTypeDefaultDescription
type"single" | "multiple""single"single keeps at most one option pressed, like a radio group; choosing the pressed option again keeps it. multiple lets each option toggle on its own.
valuestring | null (single) | readonly string[] (multiple)–Pressed value or values, for a controlled group.
defaultValuestring | null (single) | readonly string[] (multiple)–Starting value for an uncontrolled group.
onValueChange(value: string) => void (single) | (value: string[]) => void (multiple)–Called with the new value or the new list of values.
labelRequiredstring–Accessible name of the group, such as Text style or Alignment.
size"sm" | "md""md"Items 28 or 36px tall; the strip is 36 or 44px.
disabledbooleanfalseDisables every item.
childrenRequiredReactNode–ToggleGroupItem elements, as direct children so neighbouring fills can join.
classNamestring–Class on the group element.

ToggleGroupItem

One toggle. Holds an icon, text or both; icons are sized to 16px (14px at sm). Also available as ToggleGroup.Item.

PropTypeDefaultDescription
valueRequiredstring–Value this item adds or selects.
labelstring–Accessible name and native tooltip. Required when the item shows only an icon.
disabledboolean–Disables this item and removes it from arrow key movement.
childrenRequiredReactNode–Icon, text or both.
Tab
Moves into the group on one item (the last focused, else the first pressed, else the first) and out again.
Arrow keys
Move focus to the previous or next item, wrapping at the ends. Focus moves without pressing, as in a toolbar.
HomeorEnd
Focus the first or last item.
SpaceorEnter
Toggle the focused item, or select it in single mode.
  • Single mode renders role="radiogroup" with role="radio" items and aria-checked; multiple mode renders role="group" with aria-pressed buttons. Both are labelled by label.
  • Roving tabindex: only one item is a tab stop, so a toolbar with several groups stays quick to cross with Tab.
  • Icon only items take their accessible name and tooltip from label. Pressed state is shown by fill and text contrast, and exposed through aria-checked or aria-pressed.
  • The fills are aria-hidden decoration.
  • Single: one fill with a shared layoutId moves to the chosen item on the morph spring, scoped per group by a LayoutGroup; its radius is scale corrected so it keeps its shape between items of different widths.
  • Multiple: every item owns a fill that fades in over 180ms while it settles from 86% scale on the spring curve. When two neighbours are on, the fills close the gap and square off their inner corners, so a run of pressed items reads as one shape.
  • Pressing an item gives its icon and label a small 92% press and spring back; the item box never scales, so neighbours never shift.
  • Reduced motion moves the single fill instantly and replaces fades and presses with instant color changes.
  • The strip stays on one line and sizes to its items; place groups in a wrapping flex row so they stack at 320px.
  • Items are at least 36px square at md; use md on touch screens and sm in dense desktop toolbars.
  • Single mode runs one Motion layout animation per change; multiple mode is pure CSS transitions on opacity, transform and inset.
  • Item order for the roving tab stop is read from the DOM once per render of the group.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Choose ToggleGroup for tool-like options that act on something else, often icon only: text formatting, view options, filters on a canvas. Choose segmented-control for a tab-like choice between views or ranges.
  • Use type="multiple" for independent on/off options (bold, italic) and the default single type for mutually exclusive ones (alignment).
  • Give every icon only item a label. Keep items as direct children; wrapping each in another element stops neighbouring fills from joining.
  • Place several groups side by side with an 8px gap to build a toolbar; each group stays one tab stop.

The full library index for assistants is at /llms.txt.