ButtonGroup
Layout wrapper for grouping and aligning related action buttons.
The ButtonGroup primitive lets you group multiple adjacent buttons into a single horizontal or vertical unit, automatically handling border merging and corner radius clipping.
Quick Start
Group buttons together horizontally:
import { Button, ButtonGroup } from 'boltdocs/primitives'
export default function FilterGroup() {
return (
<ButtonGroup className="rounded-lg border border-subtle overflow-hidden">
<Button className="px-4 py-2 bg-surface hover:bg-soft text-body border-r border-subtle">
Tab 1
</Button>
<Button className="px-4 py-2 bg-surface hover:bg-soft text-body border-r border-subtle">
Tab 2
</Button>
<Button className="px-4 py-2 bg-surface hover:bg-soft text-body">
Tab 3
</Button>
</ButtonGroup>
)
}
Layout Configurations
Horizontal Alignment (Default)
By default, <ButtonGroup> aligns button children in a row. It removes adjacent internal border margins and applies correct left and right border radii to the outer edges.
Vertical Alignment
Set vertical to true to stack button children in a vertical column structure.
<ButtonGroup vertical className="rounded-md">
<Button className="px-4 py-2 border-b border-subtle">Stack Top</Button>
<Button className="px-4 py-2 border-b border-subtle">Stack Middle</Button>
<Button className="px-4 py-2">Stack Bottom</Button>
</ButtonGroup>
Component Props
The ButtonGroup component accepts these layout configuration props:
| Property | Type | Default | Description |
|---|---|---|---|
vertical | boolean | false | Stacks the buttons vertically when set to true. Otherwise arranges them in a horizontal flex row. |
children | ReactNode | Required | The buttons or interactive list nodes to group. |
className | string | undefined | Custom utility CSS class overrides. |
style | CSSProperties | undefined | Inline style overrides. |
Customization & states
ButtonGroup is pure layout with no state of its own. It only composes its children — joining adjacent buttons, merging their borders, and clipping corner radii. Every visual decision belongs to the theme: the container's colors, borders, and radius through className, and each child button's appearance through its own className.
| State / Slot | Mechanism |
|---|---|
vertical prop | Switches the layout between flex-row (default) and flex-col |
className | Passthrough to the flex container (e.g. rounded-lg border border-subtle) |
| First / last child | Corner radii clipped (rounded-r-none, rounded-l-none); outer corners follow your rounded-* |
| Adjacent children | Shared borders merged via -ml-px (horizontal) or -mt-px (vertical) |
| No state | No data-* attributes or interaction states — children own their own states |
Tailwind v4:
<ButtonGroup className="rounded-lg border border-subtle overflow-hidden">
<Button className="px-4 py-2 bg-surface hover:bg-soft text-body border-r border-subtle">
Left
</Button>
<Button className="px-4 py-2 bg-surface hover:bg-soft text-body">
Right
</Button>
</ButtonGroup>