BridgeHandbookDraft
For agents
Menu
ExperimentalmoleculeActions

ButtonGroup

Two or more related actions joined in one pill, such as Copy intro link · Make intro.

import { … } from "@brdgapp/ui/components/button-group"

Usage

ButtonGroup joins two or more related actions into one pill with a hairline between them, such as "Copy intro link · Make intro", or a split button where the main action sits beside a menu arrow. Set the look once on the group; every segment follows. The usual mistake is grouping actions that aren't related, which makes the pill read as a menu bar.

When to use

  • Two or three closely related actions on the same thing.
  • A split button: the main action plus a caret that opens more ways to do it (with ActionMenu's custom trigger).

When not to use

  • For one action. Use Button instead.
  • For choosing one mode of a view. Use SegmentedControl instead.
  • For unrelated actions in a toolbar. Space separate buttons instead.

Fill with -solid

Anything with white text on a colored fill uses --primary-solid or --danger-solid. The brand --primary and --error are for text, icons and focus rings; as fills they fail contrast (white on --error is 4.41:1).

One blue button per group

In each group of actions, only the single most important one is a primary (filled blue) button. The others are secondary, ghost or link. When everything is blue, nothing stands out.

Anatomy

  1. Group. A pill with a 1px border. secondary sits on a raised surface; primary is filled blue.

  2. Segment. 32px tall, 14px SemiBold. Ends are rounded by the group.

  3. Divider. A hairline between segments.

Examples

Split button

The main action beside a menu arrow.

States

RestHoverFocusPressedDisabled
Secondary
Primary
StateWhat happens
HoverThe segment fills lightly (secondary) or darkens (primary).
Focus visibleA ring inside the segment, so it isn't clipped.
Disabled30% opacity.

Behavior

  • Each segment is a native button through Base UI. With render={<Link … />} a segment stays a link.
  • The group has role="group"; give it an aria-label when the actions need context.
  • The group never clips its children, so a segment's tooltip can extend past the pill.

Do and don't

Do

Keep segments to two or three.

Don't

Turn a ButtonGroup into a toolbar of five actions.

Content

  • Segment labels follow Button: verb first, sentence case.

Accessibility

  • An icon-only segment (iconOnly) needs an aria-label.
KeysAction
TabMoves between segments.
EnterSpacePresses the focused segment.

API reference

ButtonGroup

The pill.

PropTypeDefaultDescription
variant"secondary" | "primary""secondary"Sets every segment's look.
aria-labelstring—Names the group.
classNamestring—Layout only.

ButtonGroupItem

One segment, built on Base UI Button. Extends Base UI Button.

PropTypeDefaultDescription
iconOnlybooleanfalseTighter padding for an icon segment. Needs aria-label.
renderReactElement—Draw a link with the segment's look.
classNamestring—Layout only.

Lineage

What it's built from and where it's used, read from the code. When you change it, check these too.

Built from
Nothing else in the package
Used by components
None
Used in patterns
Creating records
Used in templates
FeedRecord page

Known gaps

Where the code still differs from the system. Follow the system, not the gap.

  • Bridge OS fills the primary group with --primary. White text on it fails AA in dark mode (3.79:1), so the package uses --primary-solid.
  • Bridge OS's asChild becomes render: <ButtonGroupItem asChild><Link …/></ButtonGroupItem> → <ButtonGroupItem render={<Link …/>}>.

Sources

  • Bridge OS components.md → the button-system family; src/components/ui/button-group.tsx.