ButtonGroup
Rounds and clips a row of buttons into one control.
Installation
npx axiom add button-grouppnpm dlx axiom add button-groupyarn dlx axiom add button-groupbun x axiom add button-groupAlso copies: button. The group reads the button radius token for its corners, unless you pass radius.
Usage
import { Button } from "@/components/ui/button";
import { ButtonGroup } from "@/components/ui/button-group";
import { Separator } from "@/components/ui/separator";
<ButtonGroup bordered>
<Button variant="ghost" style={{ borderRadius: 0 }}>
Day
</Button>
<Separator orientation="vertical" />
<Button variant="ghost" style={{ borderRadius: 0 }}>
Week
</Button>
<Separator orientation="vertical" />
<Button variant="ghost" style={{ borderRadius: 0 }}>
Month
</Button>
</ButtonGroup>;The group is a View that rounds its corners and clips what’s inside. It doesn’t touch its children: every button keeps its own size, variant and disabled, and it can sit inside a wrapper such as Menu.Trigger. Square the buttons with style={{ borderRadius: 0 }} so only the outer corners stay round, and put a Separator where you want a line.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Buttons, and a Separator between them where you want a line. |
orientation | 'horizontal' | 'vertical' | 'horizontal' | Direction of the group. |
bordered | boolean | false | Draws a hairline around the group, so ghost buttons read as one outlined control. |
radius | number | button radius | Radius of the group’s outer corners. Defaults to components.button.radius. |
style | StyleProp<ViewStyle> | — | Extra styles for the container. alignSelf: 'stretch' makes it fill the row. |
The group hugs its content. To fill the row, stretch it with style and give the button that should grow flex: 1.
ButtonGroup only handles the shape. It doesn’t track a selection: for one choice among several, use SegmentedControl. For two spaced buttons, such as dialog actions, use a plain row: there’s nothing to clip.
Use cases
Split button
The main action and a chevron that opens a Menu of alternatives.
<Menu.Root>
<ButtonGroup style={{ alignSelf: "stretch" }}>
<Button style={{ borderRadius: 0, flex: 1 }} onPress={downloadPdf}>
Download PDF
</Button>
<Separator orientation="vertical" />
<Menu.Trigger asChild>
<IconButton
icon="chevron-down"
accessibilityLabel="Other formats"
variant="solid"
shape="square"
style={{ borderRadius: 0 }}
/>
</Menu.Trigger>
</ButtonGroup>
<Menu.Content>…</Menu.Content>
</Menu.Root>Stepper
Minus and plus around a value, read as one control.
<ButtonGroup bordered>
<IconButton
icon="minus"
variant="ghost"
shape="square"
size="sm"
accessibilityLabel="Remove one"
style={{ borderRadius: 0 }}
onPress={decrement}
/>
<Separator orientation="vertical" />
<Button variant="ghost" size="sm" disabled style={{ borderRadius: 0 }}>
{quantity}
</Button>
<Separator orientation="vertical" />
<IconButton
icon="plus"
variant="ghost"
shape="square"
size="sm"
accessibilityLabel="Add one"
style={{ borderRadius: 0 }}
onPress={increment}
/>
</ButtonGroup>Pill
A large radius turns the group into a pill. The buttons stay square: the group clips them.
<ButtonGroup radius={999} bordered>
<Button variant="ghost" style={{ borderRadius: 0 }}>
Day
</Button>
<Separator orientation="vertical" />
<Button variant="ghost" style={{ borderRadius: 0 }}>
Week
</Button>
<Separator orientation="vertical" />
<Button variant="ghost" style={{ borderRadius: 0 }}>
Month
</Button>
</ButtonGroup>Related
- Button
- Separator
- SegmentedControl, for a single selection among options