ButtonGroup
Related buttons, or an input and its buttons, joined into one control.
Basic
Members share borders; each keeps its own focus ring, drawn above its neighbours.
Code
<ButtonGroup label="Message actions">
<Button>Archive</Button>
<Button>Report</Button>
<Button>Snooze</Button>
</ButtonGroup>Usage
import { ButtonGroup, ButtonGroupSeparator, ButtonGroupText } from "@elements/ui/button-group";
<ButtonGroup label="Message actions">
<Button>Archive</Button>
<Button>Report</Button>
<Button>Snooze</Button>
</ButtonGroup>Examples
Vertical
orientation stacks the members.
Code
<ButtonGroup orientation="vertical" label="Media controls">
<Button icon label="Increase"><Icon name="plus" /></Button>
<Button icon label="Decrease"><Icon name="minus" /></Button>
</ButtonGroup>Sizes
Size the members; the group follows.
Code
<ButtonGroup>
<Button size="sm">Small</Button>
<Button size="sm">Button</Button>
<Button size="sm" icon label="Add"><Icon name="plus" /></Button>
</ButtonGroup>Nested
Groups inside a group sit apart; their members join.
Code
<ButtonGroup>
<ButtonGroup>
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
</ButtonGroup>
<ButtonGroup>
<Button icon label="Previous"><Icon name="arrow-left" /></Button>
<Button icon label="Next"><Icon name="arrow-right" /></Button>
</ButtonGroup>
</ButtonGroup>Separator and split button
Filled buttons need a separator to read as two.
Code
<ButtonGroup>
<Button variant="secondary">Copy</Button>
<ButtonGroupSeparator />
<Button variant="secondary">Paste</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="primary">Button</Button>
<ButtonGroupSeparator />
<Button variant="primary" icon label="More"><Icon name="chevron-down" /></Button>
</ButtonGroup>Dropdown menu
A DropdownMenu trigger joins the group: a split button.
Code
<ButtonGroup>
<Button>Follow</Button>
<DropdownMenu align="end">
<Button slot="trigger" icon label="More options"><Icon name="chevron-down" /></Button>
<DropdownMenuItem>Mute conversation</DropdownMenuItem>
<DropdownMenuItem>Mark as read</DropdownMenuItem>
<DropdownMenuItem>Report conversation</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive">Delete conversation</DropdownMenuItem>
</DropdownMenu>
</ButtonGroup>Popover and tooltip
An overlay's trigger joins the group like any button.
Code
<ButtonGroup>
<Button>Copilot</Button>
<Popover title="Agent tasks" description="Describe your task in natural language." align="end">
<Button slot="trigger" icon label="Open popover"><Icon name="chevron-down" /></Button>
<Textarea value={state.task} placeholder="Describe your task" />
</Popover>
</ButtonGroup>
<ButtonGroup>
<Tooltip content="Undo">
<Button slot="trigger" icon label="Undo"><Icon name="arrow-left" /></Button>
</Tooltip>
<Tooltip content="Redo">
<Button slot="trigger" icon label="Redo"><Icon name="arrow-right" /></Button>
</Tooltip>
</ButtonGroup>With an input
An input fills the group; buttons keep their size.
Code
<ButtonGroup>
<Input value={state.query} placeholder="Search..." attrs={{ "aria-label": "Search" }} />
<Button icon label="Search"><Icon name="search" /></Button>
</ButtonGroup>With a select
A NativeSelect or a Select joins like any member.
$
€
£
Code
<ButtonGroup>
<NativeSelect value={state.currency} options={CURRENCIES} attrs={{ "aria-label": "Currency" }} />
<Input value={state.amount} placeholder="10.00" attrs={{ "aria-label": "Amount" }} />
<Button icon label="Send"><Icon name="arrow-right" /></Button>
</ButtonGroup>
<ButtonGroup>
<Select value={state.currency} label="Currency" items={[{ value: "usd", label: "$" }, { value: "eur", label: "€" }]} />
<Input value={state.amount} placeholder="10.00" attrs={{ "aria-label": "Amount" }} />
</ButtonGroup>Text
ButtonGroupText is a segment; with htmlFor it is the input's label.
.com
Code
<ButtonGroup>
<ButtonGroupText htmlFor="url">https://</ButtonGroupText>
<Input value={state.url} attrs={{ id: "url" }} />
<ButtonGroupText>.com</ButtonGroupText>
</ButtonGroup>Right to left
The first member sits at the inline start; corners and shared borders follow.