Skip to content
Primitives

Toggle Group

Segmented control: a strong-bordered bar of Toggles divided by hairline keylines, each filling signal when active. `type="multiple"` for independent toggles, `type="single"` for a one-of-many selector.

● LIVE
npx shadcn@latest add https://okibi.cndr.dev/r/toggle-group.json

Installation

Install the theme first, then add the component:

npx shadcn@latest add https://okibi.cndr.dev/r/toggle-group.json

Install the required dependencies:

npm install @radix-ui/react-toggle-group class-variance-authority

Add the okibi building blocks it composes: toggle.

Copy the source from the Code tab above into components/ui/toggle-group.tsx. It uses the cn helper and the okibi theme tokens — install the theme first if you haven't.

Usage

import { BoldIcon, ItalicIcon, UnderlineIcon } from "lucide-react"

import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"

<ToggleGroup type="multiple" defaultValue={["bold"]}>
  <ToggleGroupItem value="bold" aria-label="Bold">
    <BoldIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="italic" aria-label="Italic">
    <ItalicIcon />
  </ToggleGroupItem>
  <ToggleGroupItem value="underline" aria-label="Underline">
    <UnderlineIcon />
  </ToggleGroupItem>
</ToggleGroup>

Anatomy

<ToggleGroup type="single" defaultValue="left">
  <ToggleGroupItem value="left" aria-label="Align left">
    {/* icon */}
  </ToggleGroupItem>
  <ToggleGroupItem value="center" aria-label="Align center">
    {/* icon */}
  </ToggleGroupItem>
</ToggleGroup>

Examples

Single

Set type="single" to bind the bar to one value at a time — e.g. a text-alignment selector.

● LIVE

Outline & sizes

The outline variant across the sm/md/lg size scale.

● LIVE

API Reference

ToggleGroup

PropTypeDefaultDescription
type"single" | "multiple"One-of-many or independent toggles.
variant"default" | "outline""default"Shared with every item.
size"sm" | "md" | "lg""md"Shared with every item.
valuestring | string[]Controlled value (string for single, array for multiple).
onValueChange(value) => voidFires when the selection changes.

Accessibility

  • Radix manages roving focus across items — one Tab stop enters the bar, then arrow keys move between toggles.
  • Each item is a real toggle exposing its pressed state; type='single' enforces one active value, type='multiple' toggles items independently.
  • Icon-only items carry no text, so each ToggleGroupItem needs its own aria-label.
  • Items set focus:z-10 so the 2px signal focus ring sits above the hairline keylines instead of being clipped.
  • The group shares variant / size with its items through context; an item can override either by passing its own prop.

Guidelines

Do

  • Set variant / size once on ToggleGroup and let context flow to the items.
  • Use type='single' for one-of-many selectors (like alignment) and type='multiple' for independent formatting toggles.
  • Give every icon-only ToggleGroupItem an aria-label.

Don't

  • Don't add the outline variant per item inside the strong-bordered bar — it double-borders against the shell; set outline on the group instead.
  • Don't pack unrelated actions into one bar; a toggle group is a segmented control for one related set of states.

On this page