Components

Button Group

Joins a set of related buttons into a single, visually-connected control — flattening the seams between adjacent members and collapsing their shared borders.

Basic usage

Wrap any number of Button elements — the group fuses their adjacent corners and borders into one segmented control. The wrapper is w-fit, so it never stretches unless you give it a width.

Orientation

Set orientation="vertical" to stack members in a column — ideal for a floating toolbar. The join flips with it: vertical members collapse their top borders instead of their left ones.

With a separator

Drop a ButtonGroupSeparator between members to split a primary action from a dropdown trigger. Unlike a standalone Separator it defaults to vertical and stretches to the full height of the group.

With static text

ButtonGroupText renders a non-interactive label that sits flush inside the group — perfect for steppers or a unit suffix. Icons inside it are auto-sized to 16px.

12

Joining an input

The group is not limited to buttons. A direct <input> child is given flex-1 so it absorbs the leftover width, and a SelectTrigger child keeps its natural width instead of stretching. Give the group a width and the input follows.

https://

Nested groups

A group whose children are themselves groups switches from fusing to spacing: the clusters are set 8px apart while each cluster stays welded internally. This is how you build a toolbar with related sets of controls without one twelve-button bar.

Props

ButtonGroup

PropTypeDefaultDescription
orientation'horizontal' | 'vertical''horizontal'Lays the children out in a row or a column, joining their adjacent edges accordingly. Whatever you pass is mirrored onto the wrapper as data-orientation; leave it off and the attribute is absent, so do not select on data-orientation="horizontal" to catch the default.
classNamestringAdditional Tailwind classes to merge onto the group wrapper.
...restReact.ComponentProps<'div'>All native div attributes are forwarded to the wrapper, which always carries role="group" and data-slot="button-group".

ButtonGroupSeparator

PropTypeDefaultDescription
orientation'horizontal' | 'vertical''vertical'Direction of the dividing line drawn between two members of the group. Note this is the opposite default from a standalone Separator.
decorativebooleantrueInherited from Separator — when true the line is hidden from the accessibility tree.
classNamestringAdditional Tailwind classes to merge.
...restReact.ComponentProps<typeof Separator>All Radix Separator props are forwarded.

ButtonGroupText

PropTypeDefaultDescription
asChildbooleanfalseMerges props onto the child element instead of rendering a div, via Radix Slot.
classNamestringAdditional Tailwind classes to merge.
...restReact.ComponentProps<'div'>All native div attributes are forwarded.

The layout recipe is exported as buttonGroupVariants if you need the joining rules on a wrapper you render yourself.

Accessibility

  • The wrapper carries role="group", signalling to assistive technology that the buttons form a single related set.
  • Each member remains an independent native <button>, so Tab, Enter, and Space behave exactly as on a standalone button.
  • The focused member is lifted above its neighbours — the group sets focus-visible:relative and focus-visible:z-10 on every child — so the brand focus outline is never clipped by an adjacent collapsed border.
  • Always pass an aria-label to icon-only members, since the joined layout offers no visible text label.
  • The separator is decorative by default and is correctly omitted from the accessibility tree.
  • Give the group its own aria-label when the set needs a collective name (“Text alignment”), and label a joined input separately — the group role does not name its members.