ToggleGroup

A segmented control for selecting one or more options from a set of toggle items

Installation

pnpm add @wandercom/design-system-web

Usage

import { ToggleGroup, ToggleGroupItem } from '@wandercom/design-system-web/ui/toggle-group';
import { IconListBullets } from '@central-icons-react/round-outlined-radius-2-stroke-1.5/IconListBullets';
import { IconLayoutGrid1 } from '@central-icons-react/round-outlined-radius-2-stroke-1.5/IconLayoutGrid1';
import { IconLayoutGrid2 } from '@central-icons-react/round-outlined-radius-2-stroke-1.5/IconLayoutGrid2';

export function Example() {
  return (
    <ToggleGroup type="single" defaultValue="list">
      <ToggleGroupItem value="list" aria-label="List view">
        <IconListBullets />
      </ToggleGroupItem>
      <ToggleGroupItem value="grid" aria-label="Grid view">
        <IconLayoutGrid1 />
      </ToggleGroupItem>
      <ToggleGroupItem value="gallery" aria-label="Gallery view">
        <IconLayoutGrid2 />
      </ToggleGroupItem>
    </ToggleGroup>
  );
}

Examples

Loading example...

The toggle group component supports icon-only, text-only, and combined icon+text content. Use type="single" for radio-like behavior or type="multiple" for checkbox-like behavior.

Sizes

Toggle groups support multiple sizes for both icon-only and text variants.

import { IconListBullets } from '@central-icons-react/round-outlined-radius-2-stroke-1.5/IconListBullets';
import { IconLayoutGrid1 } from '@central-icons-react/round-outlined-radius-2-stroke-1.5/IconLayoutGrid1';

<div className="flex flex-col gap-4">
  <ToggleGroup type="single" defaultValue="a" size="icon-sm">
    <ToggleGroupItem value="a" aria-label="Option A">
      <IconListBullets />
    </ToggleGroupItem>
    <ToggleGroupItem value="b" aria-label="Option B">
      <IconLayoutGrid1 />
    </ToggleGroupItem>
  </ToggleGroup>

  <ToggleGroup type="single" defaultValue="a" size="icon-md">
    <ToggleGroupItem value="a" aria-label="Option A">
      <IconListBullets />
    </ToggleGroupItem>
    <ToggleGroupItem value="b" aria-label="Option B">
      <IconLayoutGrid1 />
    </ToggleGroupItem>
  </ToggleGroup>

  <ToggleGroup type="single" defaultValue="a" size="icon-lg">
    <ToggleGroupItem value="a" aria-label="Option A">
      <IconListBullets />
    </ToggleGroupItem>
    <ToggleGroupItem value="b" aria-label="Option B">
      <IconLayoutGrid1 />
    </ToggleGroupItem>
  </ToggleGroup>

  <ToggleGroup type="single" defaultValue="a" size="sm">
    <ToggleGroupItem value="a">Small</ToggleGroupItem>
    <ToggleGroupItem value="b">Option</ToggleGroupItem>
  </ToggleGroup>

  <ToggleGroup type="single" defaultValue="a" size="md">
    <ToggleGroupItem value="a">Medium</ToggleGroupItem>
    <ToggleGroupItem value="b">Option</ToggleGroupItem>
  </ToggleGroup>

  <ToggleGroup type="single" defaultValue="a" size="lg">
    <ToggleGroupItem value="a">Large</ToggleGroupItem>
    <ToggleGroupItem value="b">Option</ToggleGroupItem>
  </ToggleGroup>
</div>

Single vs multiple selection

Use type="single" when only one option can be selected at a time (like radio buttons). Use type="multiple" when multiple options can be selected simultaneously (like checkboxes).

import { IconBold } from '@central-icons-react/round-outlined-radius-2-stroke-1.5/IconBold';
import { IconItalic } from '@central-icons-react/round-outlined-radius-2-stroke-1.5/IconItalic';
import { IconUnderline } from '@central-icons-react/round-outlined-radius-2-stroke-1.5/IconUnderline';

<div className="flex flex-col gap-4">
  <div>
    <p className="text-secondary text-sm mb-2">Single selection (radio behavior)</p>
    <ToggleGroup type="single" defaultValue="bold" size="icon-sm">
      <ToggleGroupItem value="bold" aria-label="Bold">
        <IconBold />
      </ToggleGroupItem>
      <ToggleGroupItem value="italic" aria-label="Italic">
        <IconItalic />
      </ToggleGroupItem>
      <ToggleGroupItem value="underline" aria-label="Underline">
        <IconUnderline />
      </ToggleGroupItem>
    </ToggleGroup>
  </div>

  <div>
    <p className="text-secondary text-sm mb-2">Multiple selection (checkbox behavior)</p>
    <ToggleGroup type="multiple" defaultValue={['bold', 'italic']} size="icon-sm">
      <ToggleGroupItem value="bold" aria-label="Bold">
        <IconBold />
      </ToggleGroupItem>
      <ToggleGroupItem value="italic" aria-label="Italic">
        <IconItalic />
      </ToggleGroupItem>
      <ToggleGroupItem value="underline" aria-label="Underline">
        <IconUnderline />
      </ToggleGroupItem>
    </ToggleGroup>
  </div>
</div>

Controlled state

Use value and onValueChange for controlled state management.

import { IconListBullets } from '@central-icons-react/round-outlined-radius-2-stroke-1.5/IconListBullets';
import { IconLayoutGrid1 } from '@central-icons-react/round-outlined-radius-2-stroke-1.5/IconLayoutGrid1';

const [value, setValue] = useState('list');

<ToggleGroup type="single" value={value} onValueChange={setValue} size="icon-sm">
  <ToggleGroupItem value="list" aria-label="List view">
    <IconListBullets />
  </ToggleGroupItem>
  <ToggleGroupItem value="grid" aria-label="Grid view">
    <IconLayoutGrid1 />
  </ToggleGroupItem>
</ToggleGroup>

Disabled state

Individual items or the entire group can be disabled.

<div className="flex flex-col gap-4">
  <ToggleGroup type="single" defaultValue="a" size="sm" disabled>
    <ToggleGroupItem value="a">Disabled</ToggleGroupItem>
    <ToggleGroupItem value="b">Group</ToggleGroupItem>
  </ToggleGroup>

  <ToggleGroup type="single" defaultValue="a" size="sm">
    <ToggleGroupItem value="a">Active</ToggleGroupItem>
    <ToggleGroupItem value="b" disabled>Disabled Item</ToggleGroupItem>
    <ToggleGroupItem value="c">Active</ToggleGroupItem>
  </ToggleGroup>
</div>

Props

ToggleGroup

type

'single' | 'multiple'
Selection mode. Use 'single' for radio-like behavior, 'multiple' for checkbox-like behavior.

size?

'sm' | 'md' | 'lg' | 'icon-sm' | 'icon-md' | 'icon-lg'
Size variant. Icon sizes are square, text sizes have horizontal padding. Defaults to 'icon-sm'.

defaultValue?

string | string[]
Default selected value(s). String for type='single', string array for type='multiple'.

value?

string | string[]
Controlled selected value(s).

onValueChange?

(value: string | string[]) => void
Callback fired when the selection changes.

disabled?

boolean
Disables all toggle items in the group.

rovingFocus?

boolean
Enables roving focus keyboard navigation. Defaults to true.

orientation?

'horizontal' | 'vertical'
Orientation for keyboard navigation. Defaults to 'horizontal'.

loop?

boolean
Whether keyboard navigation should loop. Defaults to true.

className?

string
Additional CSS classes to apply.

ToggleGroupItem

value

string
The unique value of this toggle item.

size?

'sm' | 'md' | 'lg' | 'icon-sm' | 'icon-md' | 'icon-lg'
Override the size from the parent ToggleGroup.

disabled?

boolean
Disables this specific toggle item.

aria-label?

string
Accessible label for icon-only toggle items.

className?

string
Additional CSS classes to apply.

Accessibility

The ToggleGroup component is built on Radix UI primitives and follows WAI-ARIA guidelines for toggle button groups.

Keyboard interaction:

  • ArrowRight / ArrowDown - Move focus to the next item
  • ArrowLeft / ArrowUp - Move focus to the previous item
  • Space - Toggle the focused item
  • Enter - Toggle the focused item
  • Home - Move focus to the first item
  • End - Move focus to the last item

Roving focus is enabled by default. When using type="single", the group behaves like a radio group semantically. When using type="multiple", it behaves like a group of checkboxes.

Always provide an aria-label for icon-only toggle items to ensure screen readers can announce the purpose of each option. The component manages aria-pressed state automatically.

ToggleGroup