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 StartLink

Group buttons together horizontally:

tsx
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 ConfigurationsLink

Horizontal Alignment (Default)Link

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 AlignmentLink

Set vertical to true to stack button children in a vertical column structure.

tsx
<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 PropsLink

The ButtonGroup component accepts these layout configuration props:

PropertyTypeDefaultDescription
verticalbooleanfalseStacks the buttons vertically when set to true. Otherwise arranges them in a horizontal flex row.
childrenReactNodeRequiredThe buttons or interactive list nodes to group.
classNamestringundefinedCustom utility CSS class overrides.
styleCSSPropertiesundefinedInline style overrides.

Customization & statesLink

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 / SlotMechanism
vertical propSwitches the layout between flex-row (default) and flex-col
classNamePassthrough to the flex container (e.g. rounded-lg border border-subtle)
First / last childCorner radii clipped (rounded-r-none, rounded-l-none); outer corners follow your rounded-*
Adjacent childrenShared borders merged via -ml-px (horizontal) or -mt-px (vertical)
No stateNo data-* attributes or interaction states — children own their own states

Tailwind v4:

tsx
<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>
Last updated on October 18, 2026

Was this page helpful?