Skip to content

Toggle group

Joins toggles in a row, one or several pressed, like Day, Week and Month.

Library
What’s this?

Installation

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

The CLI installs the Radix or Base UI file to match your project, with what it builds on: toggle.

If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.

When to use

Use it

  • To pick one of a few related options in a compact control, like a calendar's Day, Week and Month.
  • To turn several related options on and off, like text formatting or the days a meeting repeats.
  • The options are short labels or icons that fit on one line.
  • In place of Lightning's radio group with type="button".

Don't use it

  • One option turns on or off on its own. Use Toggle.
  • The choice is a form field with a label and validation. Use Radio Group or Checkbox.
  • The options switch between panels of content. Use Tabs.
  • The buttons run actions and don't stay pressed. Use Button Group.
  • There are more than about five options, or long labels. Use Select.

Usage

The two bases take different props for the choice mode and the value. In Radix projects type is required, "single" or "multiple", and a single-choice value is a string. In Base UI projects a group is single-choice unless it takes multiple, and the value is always an array.

import { useState } from "react"

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

export function ListDisplayPicker() {
  const [display, setDisplay] = useState("table")

  return (
    <ToggleGroup
      type="single"
      variant="outline"
      value={display}
      onValueChange={(next) => next && setDisplay(next)}
      aria-label="Display as"
    >
      <ToggleGroupItem value="table">Table</ToggleGroupItem>
      <ToggleGroupItem value="kanban">Kanban</ToggleGroupItem>
      <ToggleGroupItem value="split">Split view</ToggleGroupItem>
    </ToggleGroup>
  )
}

In Base UI projects, leave out type and pass value={[display]} with onValueChange={(next) => next[0] && setDisplay(next[0])}. Pressing the pressed item releases it, so onValueChange gets "" in Radix projects and [] in Base UI projects. The checks keep one display pressed.

spacing on ToggleGroup sets the gap between items, in the same steps as gap-* classes: spacing={1} is 4px. At 0, the default, the items join into one control.

Examples

Multiple

Weekdays where several can be pressed, set with `type="multiple"` (`multiple` in Base UI projects), Mon and Wed pressed.

Icons

Icon-only `variant="outline"` formatting toggles, joined and each named with `aria-label`, Bold pressed.

Spacing

Bare icon toggles 4px apart, set with `spacing={1}` on `ToggleGroup`, Bold pressed.

Helpful or not

A yes or no question as two `variant="outline"` items apart by `spacing={2}`, Helpful pressed, its thumbs swappable for smiles or a check and an X.

Was this article helpful?

Disabled

A single-choice group set with `disabled` on `ToggleGroup`, Week pressed.

API reference

PartBuilt on
ToggleGroupRadix ToggleGroup.Root (opens in a new tab)
ToggleGroupItemRadix ToggleGroup.Item (opens in a new tab)

ToggleGroup

PropTypeDefault
orientation"horizontal" | "vertical""horizontal"
variant"default" | "outline"
size"default" | "sm" | "lg"
spacingnumber0

ToggleGroupItem

PropTypeDefault
variant"default" | "outline""default"
size"default" | "sm" | "lg""default"

SLDS mapping

ToggleGroup is SLDS's radio button group for one choice and its checkbox button group for several, and each ToggleGroupItem is a Toggle. An item with text is the group's label (slds-radio_button__label or slds-checkbox_button__label). An icon-only item, with aria-label, is a button in slds-button-group-list, as in SLDS's rich text toolbar. With spacing above 0, items are separate Toggles.

Known gaps:

  • SLDS's radio and checkbox button groups are a little taller than its other controls. Ours match Button's height, so they line up with buttons and inputs.
  • SLDS has no vertical button group. A vertical group mirrors the horizontal one.
PropValueSLDSNotes
variantdefaultslds-button_icon-containerBare toggles. Joined, only a pressed item shows its fill.
variantoutlineslds-radio_button-grouptype="single" is slds-radio_button-group, type="multiple" slds-checkbox_button-group; they look the same. Icon-only items are slds-button-group-list with slds-button_icon-border-filled.
sizedefaultslds-radio_buttonToggle's default height.
sizesmnoneToggle's small height.
sizelgnoneToggle's large height.

Keyboard interactions

Keys Action
Right Arrow, Left Arrow Moves to the next or previous item. Focus doesn't press it.
Down Arrow, Up Arrow The same, in a group with orientation="vertical".
Space, Enter Presses or releases the focused item.

Accessibility

  • Name the group with aria-label, and each icon-only item with aria-label. Keep the names the same when pressed; the pressed state carries the change.

Motion

  • In Cosmos, outline and pressed items lift on hover as Toggle's do, over 150ms. Lightning Blue sets the lift to none.
  • The lift runs with reduced motion too.

Responsive behavior

  • The group is as wide as its items and doesn't wrap, and labels stay on one line. Keep it to a few short items, or use Select on narrow screens.

Rules

  • Never give aria-label to an item with visible text. The label decides whether the item draws as a labelled segment or an icon button, with its padding and borders.
  • Use variant="outline" for joined segments. For a row of separate icon toggles, use bare items with spacing, as the Spacing example shows.
  • Never override item colors, radius or height with utility classes. The tokens carry each theme.