Actions

ToggleGroup

A row of related toggles that share one value, such as text alignment or bold, italic and underline in a toolbar. One toggle is pressed at a time unless multiple is set, which makes the value a list. The arrow keys move between toggles, and each keeps its name with aria-pressed for its state.

Text style
Alignment

Install

Once per app, with Tailwind CSS v4 and an @/* path alias (Ouro HX is built on Base UI, so --base base; skip -t in an existing app):

npx shadcn@latest init --base base --preset nova --yes --no-monorepo
npx shadcn@latest add ourostack/ouro-ui/ouro-base#v1.2.13

Then the component. From v0.8.0 it installs only the helpers it imports and never touches your stylesheet (Installing):

npx shadcn@latest add ourostack/ouro-ui/toggle-group#v1.2.13

Or, with the @ouro namespace set up:

npx shadcn@latest add @ouro/ouro-base @ouro/toggle-group

Its tests, stories and Playwright spec are optional. They need Vitest 4.1.11 or later, and from v0.8.0 never change a version your app has (Testing):

npx shadcn@latest add ourostack/ouro-ui/toggle-group#v1.2.13 ourostack/ouro-ui/toggle-group-tests#v1.2.13
import { ToggleGroup } from "@/components/ouro/toggle/toggle-group";

Paths use shadcn's default @/ alias; the CLI rewrites them to yours.

Example

<ToggleGroup
  label="Text style"
  hideLabel
  multiple
  items={[
    { value: "bold", label: "Bold", icon: BoldIcon, hideLabel: true },
    { value: "italic", label: "Italic", icon: ItalicIcon, hideLabel: true },
  ]}
  value={styles}
  onValueChange={setStyles}
/>

Use instead when

  • Use SegmentedControl instead when exactly one choice is always selected and switches a view.
  • Use RadioGroup or CheckboxGroup instead for a form value that is submitted, and one Toggle for a single on/off button.

Props

The props the modes share. Type: ToggleGroupProps.

className
Type: string
Layout only: margins, grid placement (mt-4). Appearance classes warn in development.
disabled
Type: boolean
Disables every toggle.
hideLabel
Type: boolean
Hides the group's label visually; it still names the group. Set it on a toolbar whose toggles say what it is.
items (required)
Type: readonly ToggleGroupItem[]
The toggles, in order.
label (required)
Type: string
Names the group ("Text style"). Shown above it unless hideLabel is set; screen readers always hear it.
ref
Type: Ref<HTMLDivElement>
Reaches the group element (role="group").
size
Type: "sm" | "md" | "lg"
Default: "md"
Every toggle's size, as Button's. shadcn's default is md.
variant
Type: "outline" | "plain"
Default: "plain"
plain toggles have no border until pressed; outline ones always have one. shadcn's default is plain.

Modes

ToggleGroupProps is a union: pass the props of exactly one mode. Mixing them is a type error.

Multiple: ToggleGroupMultipleProps

With multiple, any number of toggles pressed: the value is a list of item values.

defaultValue
Type: readonly string[]
Default: []
The toggles pressed first, when the group keeps its own state.
multiple (required)
Type: true
Allows several toggles pressed at once, and makes the value a list.
onValueChange
Type: ((value: string[]) => void)
Called with the pressed toggles' values, in item order.
value
Type: readonly string[]
The pressed toggles' values, when you control them. Pair it with onValueChange.

Single: ToggleGroupSingleProps

One toggle pressed at a time, the default: the value is one item's value, or null for none.

defaultValue
Type: string | null
Default: null
The toggle pressed first, when the group keeps its own state.
multiple
Type: false
Allows several toggles pressed at once, and makes the value a list.
onValueChange
Type: ((value: string | null) => void)
Called with the pressed toggle's value, or null when the pressed one is pressed again.
value
Type: string | null
The pressed toggle's value, or null for none, when you control it. Pair it with onValueChange.

Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

  • children: Not a prop. The toggles come from items: <ToggleGroup items={[{ value: "bold", label: "Bold" }]}>.
  • onChange: Not a prop. Ouro UI uses onValueChange, which gets the value: <ToggleGroup onValueChange={(value) => ...}>.
  • options: Not a prop. Ouro UI uses items: <ToggleGroup items={[{ value, label }]}>.
  • type: Not a prop. One toggle at a time is the default; multiple allows several: <ToggleGroup multiple>.

className is for layout only

Pass margins, width and grid placement (mt-4, w-full, col-span-2). Your classes always win over Ouro UI's: ToggleGroup merges className last with cn (tailwind-merge), so a class that conflicts with its own replaces it.layout-classes

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (hover:, sm:) and any ! are removed, it starts with bg-, text-, border-, rounded-, shadow-, font-, ring-, from-, via-, to-, fill- or stroke-, or is border, rounded, shadow or ring, or has a dark: variant. Text wrapping, overflow and table layout classes (text-wrap, text-ellipsis, border-collapse) are layout and do not warn.

Alignment classes (text-center) warn too: set alignment on a parent element.

Types

ToggleGroupItem

One toggle in a ToggleGroup.

interface ToggleGroupItem {
  /** Identifies the toggle: `value`, `defaultValue` and `onValueChange` use it. Unique within the group. */
  value: string;
  /** The toggle's name, shown unless `hideLabel` is set. It stays the same while pressed. */
  label: string;
  /** Icon before the label, or alone with `hideLabel`. Pass the component: `icon: BoldIcon`. */
  icon?: ToggleIcon | undefined;
  /** Shows only the icon; the label stays the toggle's name for screen readers. */
  hideLabel?: boolean | undefined;
  /** Shows the toggle but keeps it from being pressed. */
  disabled?: boolean | undefined;
}

Claim sources