Button Group
Related options in one connected row, with exactly one selected: to switch views or filter results. The first option sits at the inline start, the right in Arabic.
Preview
Mirrored is the same English content laid out right to left: it separates a mirroring bug from a translation one.
Installation
npx shadcn@latest add @ritla/button-groupDependencies it brings: @base-ui/react, @phosphor-icons/react
Usage
import { ButtonGroup, ButtonGroupItem } from "@/components/ui/button-group";<ButtonGroup aria-label="Period" defaultValue="week">
<ButtonGroupItem value="day" label="Day" />
<ButtonGroupItem value="week" label="Week" />
<ButtonGroupItem value="month" label="Month" />
</ButtonGroup>Examples
Styles
outline (default), tonal and filled. The selected option takes the pressed Button fill; dividers and the outline share one color. A disabled option stays visible.
Sizes
Button's heights: 56, 48, 40 and 32px. The tap target stays at least 48px at sm and xs.
Icons only
showLabel={false} leaves the icon alone for compact toolbars; label stays the name screen readers announce.
Filter and keyboard
A controlled version with value and onValueChange; the counts follow the numerals setting. Tab enters the group once and the arrows move between options: in Arabic, ArrowLeft is next.
API reference
ButtonGroup
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "outline" | "tonal" | "filled" | "outline" | Figma's Style. |
size | "lg" | "md" | "sm" | "xs" | "lg" | Figma's Size: 56, 48, 40 and 32px. |
value | string | The selected option's value (controlled). | |
defaultValue | string | The option selected at first. In Figma, the first one. | |
onValueChange | (value: string) => void | Called with the new value. Pressing the selected option again keeps it selected. | |
disabled | boolean | false | Disables every option. |
aria-label | string | The group's name (“Period”, “View”). |
ButtonGroupItem
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | Identifies the option. | |
label | string | Required. Figma's Label, and the option's name even when the text is hidden. | |
showLabel | boolean | true | Figma's Show Label. |
iconLeading | IconComponent | Icon leading: an icon before the label. | |
disabled | boolean | false | State = Disabled for this option. |
Accessibility
Keyboard
Keys are written for left-to-right. In right-to-left the arrow keys swap: the one pointing toward the reading direction moves forward.
| Key | Action |
|---|---|
| Tab | Enters the group once, on the selected option; the next press leaves it. |
| ArrowRightArrowLeft | Moves to the next or previous option and wraps at the ends. Flips in Arabic. |
| EnterSpace | Selects the focused option. |
ARIA
- A
role="group"named byaria-label; each option is a native button witharia-pressed. - Selection doesn't rely on color alone:
aria-pressedannounces it, and one option always stays selected. - In icons-only mode,
labelbecomes the option'saria-label.
Arabic and RTL notes
Mirrors
- Option order mirrors: the first sits at the inline start (the right in Arabic), and dividers are logical borders that follow the direction.
- Arrow keys follow the reading direction: ArrowLeft moves to the next option in Arabic.
Does not mirror
- Non-directional icons (list, grid, map) don't mirror; only directional ones flip through
<Icon>.
- Numerals
- Counts inside options (“Open 12”) are formatted with
formatNumberand follow the numerals setting. - Arabic typography
body-16(body-14atxs) Semibold like Button. Options hug their text, so shorter Arabic labels aren't stretched.- Mixed-direction text
- A Latin name at the end of an Arabic option (“عرض Kanban”) renders correctly; in the middle, wrap it in
<bdi>.