Button Group
Segments sharing one rounded chrome with inner dividers -- row actions or a split button.
Usage
import {
ButtonGroup,
ButtonGroupButton,
ButtonGroupSeparator,
ButtonGroupText,
} from '@epilot/spark-ui/button-group'<ButtonGroup aria-label="Row actions">
<ButtonGroupButton>Edit</ButtonGroupButton>
<ButtonGroupSeparator />
<ButtonGroupButton>Delete</ButtonGroupButton>
</ButtonGroup>ButtonGroup is the shared chrome: it owns the rounded box, the fill, and the
foreground color, and its segments (ButtonGroupButton, ButtonGroupText) are
chrome-less -- they inherit the group's look and only add their own hover and
focus states. ButtonGroupSeparator is an author-placed divider: put one
between segments that need a visual break, and skip it between segments that
read as one action.
This is a layout group, not a toolbar: segments are independent tab stops in DOM order, not a roving-tabindex widget. For a single-select group of segments, use Segmented Control instead.
Examples
Row actions
A plain group of segments sharing one chrome.
Split button with a menu
Pass a ButtonGroupButton as render to Dropdown Menu's
trigger to build a split button: a primary action segment plus a chevron
segment that opens a menu of related actions.
API Reference
ButtonGroup
| Prop | Type | Default | Description |
|---|---|---|---|
styleVariant | 'solid' | 'soft' | 'surface' | 'ghost' | 'outline' | 'soft' | Always emitted as data-style; segments read the inherited --spark-style-* tokens. |
color | 'accent' | 'neutral' | 'success' | 'warning' | 'danger' | 'neutral' | accent omits data-accent-color; neutral→gray, success→green, warning→orange, danger→red. |
size | 'small' | 'default' | 'default' | Sets the group's height, font size, and icon size (h-9/h-10, matching Button's scale). Inherits to segments. |
The ends follow the theme radius knob (same expression as Button).
The group also forwards all other div attributes, including className
(merged with the base styling), and a ref to the root <div>. Pass
aria-label when segments don't self-describe -- the root carries
role="group".
ButtonGroupButton
An interactive segment. Renders Base UI Button,
so it accepts all of Button's underlying props, including render for
polymorphism (e.g. a split-button dropdown trigger) and disabled.
ButtonGroupText
An inert segment for status/label text -- no hover, no cursor, no keyboard interaction. Use it as the first segment of a status pill.
ButtonGroupSeparator
A thin aria-hidden divider (bg-current, so it recolors with the group's
color). Place it between segments yourself; it is not inserted
automatically.
Accessibility
- The root carries
role="group"-- document your ownaria-labelwhen segments don't self-describe. - Segments are independent tab stops in DOM order. There is no roving tabindex or arrow-key navigation; that belongs to Segmented Control.
ButtonGroupButtonmapsdisabledto nativedisabled/aria-disabledsemantics via Base UI's Button, the same as the standalone Button.- Give an icon-only segment its own
aria-label. ButtonGroupTextnever carriesrole="status"-- add that yourself on the consumer side if the text should be announced on change.- The focus ring is inset (
focus-visible:inset-ring-2) because the group clips its segments withoverflow-hidden.