Toggle group
Joins toggles in a row, one or several pressed, like Day, Week and Month.
Installation
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.
Disabled
A single-choice group set with `disabled` on `ToggleGroup`, Week pressed.
API reference
| Part | Built on |
|---|---|
ToggleGroup | Radix ToggleGroup.Root (opens in a new tab) |
ToggleGroupItem | Radix ToggleGroup.Item (opens in a new tab) |
ToggleGroup
| Prop | Type | Default |
|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" |
variant | "default" | "outline" | |
size | "default" | "sm" | "lg" | |
spacing | number | 0 |
ToggleGroupItem
| Prop | Type | Default |
|---|---|---|
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.
| Prop | Value | SLDS | Notes |
|---|---|---|---|
variant | default | slds-button_icon-container | Bare toggles. Joined, only a pressed item shows its fill. |
variant | outline | slds-radio_button-group | type="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. |
size | default | slds-radio_button | Toggle's default height. |
size | sm | none | Toggle's small height. |
size | lg | none | Toggle'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 witharia-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-labelto 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 withspacing, as the Spacing example shows. - Never override item colors, radius or height with utility classes. The tokens carry each theme.