ButtonGroup merges related buttons into one control — a split Publish ▾, pager arrows, a search field with its button. ToggleGroup adds a selected state with roving focus — view switches, chart ranges, text alignment and formatting. Toggle is a single pressed/unpressed button.
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { Button, ButtonGroup, ToggleGroup, ToggleGroupItem } from "@vamos-ui/react";
<ButtonGroup aria-label="Post actions">
<Button>Preview</Button>
<Button>Edit</Button>
</ButtonGroup>
<ToggleGroup aria-label="View" defaultValue="board">
<ToggleGroupItem value="list">List</ToggleGroupItem>
<ToggleGroupItem value="board">Board</ToggleGroupItem>
</ToggleGroup>ButtonGroup has no roving focus: every button is its own tab stop. Use ToggleGroup when the buttons are a set of states.
Choosing: a form value → RadioGroup (segmented); a view or toolbar state → ToggleGroup; independent actions → ButtonGroup.
Examples
Split button
A primary group with ButtonGroupSeparator, so the merged edge stays visible on the accent fill. The chevron opens a Dropdown Menu.
With an input
Inputs and ButtonGroupText segments merge the same way; the focused child is raised so its ring isn't clipped.
Pager
variant and size on the group apply to direct Button / IconButton children that don't set their own.
Vertical
orientation="vertical" — map zoom controls. attached={false} keeps a gap instead of merging.
View switch (ToggleGroup)
The default "segmented" look: an inset track and a raised thumb. Single mode never empties unless allowEmpty is set.
Editor toolbar
type="multiple" for B / I / U, "outline" for attached alignment buttons, and a lone Toggle. Icon-only items take a label.
API
ButtonGroup
| Prop | Type | Default |
|---|---|---|
attachedMerge borders and corners; false keeps an 8px gap. | boolean | true |
orientationDirection; corners merge with logical properties (RTL-safe). | "horizontal" | "vertical" | "horizontal" |
variantDefault for direct Button / IconButton children. | Button variant | — |
sizeDefault size for direct Button / IconButton children. | "xs" | "sm" | "md" | "lg" | — |
aria-labelRecommended: names the group. | string | — |
ButtonGroupSeparator
| Prop | Type | Default |
|---|---|---|
orientationHairline between attached buttons that share a fill. | "vertical" | "horizontal" | "vertical" |
ButtonGroupText
| Prop | Type | Default |
|---|---|---|
sizeA static segment ("21–40 of 340", a prefix or unit). | "xs" | "sm" | "md" | "lg" | "md" |
ToggleGroup
| Prop | Type | Default |
|---|---|---|
typeOne active item, or independent pressed states. | "single" | "multiple" | "single" |
value / defaultValueActive item(s). | string | string[] | — |
onValueChangeCalled with the next value. | (value) => void | — |
allowEmptySingle only: allow deselecting the active item. | boolean | false |
variantInset track + thumb, attached bordered buttons, or loose toolbar buttons. | "segmented" | "outline" | "ghost" | "segmented" |
sizemd follows --control-h. | "xs" | "sm" | "md" | "lg" | "md" |
orientationLayout and arrow-key axis. | "horizontal" | "vertical" | "horizontal" |
blockFull width, items share the space. | boolean | — |
rovingFocus / loopArrow-key navigation behaviour. | boolean | true |
ToggleGroupItem / Toggle
| Prop | Type | Default |
|---|---|---|
valueToggleGroupItem only. Required. | string | — |
labelAccessible name + tooltip for icon-only items. | string | — |
pressed / defaultPressed / onPressedChangeToggle only: aria-pressed state. | boolean | — |
variantToggle only. | "ghost" | "outline" | "ghost" |
sizeToggle only (items take the group size). | "xs" | "sm" | "md" | "lg" | "md" |
disabledSkipped by arrow keys. | boolean | — |