Button Group
Glue related buttons, inputs and menus into one tidy row or column with shared borders and rounded ends.
Preview
Usage
import {
ButtonGroup,
ButtonGroupSeparator,
ButtonGroupText,
} from '@vitnode/core/components/ui/button-group'<ButtonGroup aria-label="Message actions">
<Button variant="outline">Archive</Button>
<Button variant="outline">Report</Button>
<Button variant="outline">Snooze</Button>
</ButtonGroup>Inner borders merge and only the outer corners stay round. The buttons need no extra props.
Orientation
<ButtonGroup aria-label="Zoom" orientation="vertical">
<Button aria-label="Zoom in" size="icon-sm" variant="outline">
<ZoomInIcon />
</Button>
<Button aria-label="Zoom out" size="icon-sm" variant="outline">
<ZoomOutIcon />
</Button>
</ButtonGroup>Nested groups
Groups inside a group get a small gap between them, the classic toolbar look.
<ButtonGroup aria-label="Message actions">
<ButtonGroup>
<Button aria-label="Go back" size="icon" variant="outline">
<ArrowLeftIcon />
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline">Archive</Button>
<Button variant="outline">Report</Button>
</ButtonGroup>
</ButtonGroup>Separator
Borderless variants like secondary blur into one blob. Put a
ButtonGroupSeparator between them.
<ButtonGroup aria-label="Text alignment">
<Button aria-label="Align left" size="icon" variant="secondary">
<AlignLeftIcon />
</Button>
<ButtonGroupSeparator />
<Button aria-label="Align center" size="icon" variant="secondary">
<AlignCenterIcon />
</Button>
</ButtonGroup>Inside a vertical group, use <ButtonGroupSeparator orientation="horizontal" />.
With text
ButtonGroupText is a non-interactive segment, like a counter. Use render
to swap the element, for example to a <label>.
<ButtonGroup aria-label="Quantity">
<Button aria-label="Decrease quantity" size="icon" variant="outline">
<MinusIcon />
</Button>
<ButtonGroupText aria-live="polite">{quantity}</ButtonGroupText>
<Button aria-label="Increase quantity" size="icon" variant="outline">
<PlusIcon />
</Button>
</ButtonGroup>With input
An Input stretches to fill the free space.
<ButtonGroup className="w-full max-w-sm">
<Input aria-label="Search members" placeholder="Search members..." />
<Button aria-label="Search" size="icon" variant="outline">
<SearchIcon />
</Button>
</ButtonGroup>Split button
Pair a button with a Dropdown Menu trigger.
<ButtonGroup>
<Button variant="outline">Snooze</Button>
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button
aria-label="More snooze options"
size="icon"
variant="outline"
/>
}
>
<ChevronDownIcon />
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>Later today</DropdownMenuItem>
<DropdownMenuItem>Next week</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</ButtonGroup>Sizes
The group follows its buttons. Use the same size on all of them so heights
match.
Accessibility
- The group has
role="group". Give it anaria-labeloraria-labelledby. - Icon-only buttons need their own
aria-label. - A focused button lifts above its neighbours, so the focus ring never hides.
- Borders and corners flip correctly in right-to-left languages.
- Need a selected state, like a segmented control? Use Toggle Group.
Props
ButtonGroup
Prop
Type
ButtonGroupText
Prop
Type
ButtonGroupSeparator
Prop
Type
All parts accept className.