Button Group
Group related actions, inputs, and menus with shared borders and focus rings.
<ButtonGroup> <Button variant="outline">Archive</Button> <Button variant="outline">Report</Button></ButtonGroup>Usage
import {
ButtonGroup,
ButtonGroupSeparator,
ButtonGroupText,
} from "@reva/ui";Icon-only controls in a group use Icon Button (Reva does not use shadcn Button size="icon" / icon-sm).
Composition
Use the following composition to build a ButtonGroup:
ButtonGroup
├── Button or Input
├── ButtonGroupSeparator
└── ButtonGroupTextNest ButtonGroup to cluster controls with spacing between clusters (see Toolbar below).
Examples
Toolbar
Nested groups and a Dropdown Menu with a radio sub-menu—adapted from shadcn. Keep Button and IconButton on the same size in a cluster (here, sm). Add useState for label / setLabel, import icons from @phosphor-icons/react/ssr, and mark the file "use client" when you copy this pattern.
<ButtonGroup> <ButtonGroup className="hidden sm:flex"> <IconButton variant="outline" size="sm" aria-label="Go Back"> <ArrowLeft /> </IconButton> </ButtonGroup> <ButtonGroup> <Button variant="outline" size="sm">Archive</Button> <Button variant="outline" size="sm">Report</Button> </ButtonGroup> <ButtonGroup> <Button variant="outline" size="sm">Snooze</Button> <DropdownMenu> <DropdownMenuTrigger asChild> <IconButton variant="outline" size="sm" aria-label="More Options"> <DotsThree /> </IconButton> </DropdownMenuTrigger> <DropdownMenuContent align="end" className="w-40"> <DropdownMenuGroup> <DropdownMenuItem> <EnvelopeOpen /> Mark as Read </DropdownMenuItem> <DropdownMenuItem> <Archive /> Archive </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem> <Clock /> Snooze </DropdownMenuItem> <DropdownMenuItem> <CalendarPlus /> Add to Calendar </DropdownMenuItem> <DropdownMenuItem> <FunnelSimple /> Add to List </DropdownMenuItem> <DropdownMenuSub> <DropdownMenuSubTrigger> <Tag /> Label As... </DropdownMenuSubTrigger> <DropdownMenuSubContent> <DropdownMenuRadioGroup value={label} onValueChange={setLabel}> <DropdownMenuRadioItem value="personal">Personal</DropdownMenuRadioItem> <DropdownMenuRadioItem value="work">Work</DropdownMenuRadioItem> <DropdownMenuRadioItem value="other">Other</DropdownMenuRadioItem> </DropdownMenuRadioGroup> </DropdownMenuSubContent> </DropdownMenuSub> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem variant="destructive"> <TrashSimple /> Trash </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> </ButtonGroup></ButtonGroup>Orientation
Set orientation to vertical for a stacked group.
<ButtonGroup orientation="vertical" aria-label="Media controls" className="h-fit"> <IconButton variant="outline" size="sm" aria-label="Increase"> <Plus /> </IconButton> <IconButton variant="outline" size="sm" aria-label="Decrease"> <Minus /> </IconButton></ButtonGroup>Size
Control size with each Button or IconButton size prop (xs | sm | default | lg).
<div className="flex flex-col items-center justify-center gap-8"> <ButtonGroup> <Button variant="outline" size="xs">Extra small</Button> <Button variant="outline" size="xs">Button</Button> <Button variant="outline" size="xs">Group</Button> <IconButton variant="outline" size="xs" aria-label="Add"> <Plus /> </IconButton> </ButtonGroup> <ButtonGroup> <Button variant="outline" size="sm">Small</Button> <Button variant="outline" size="sm">Button</Button> <Button variant="outline" size="sm">Group</Button> <IconButton variant="outline" size="sm" aria-label="Add"> <Plus /> </IconButton> </ButtonGroup> <ButtonGroup> <Button variant="outline">Default</Button> <Button variant="outline">Button</Button> <Button variant="outline">Group</Button> <IconButton variant="outline" aria-label="Add"> <Plus /> </IconButton> </ButtonGroup></div>Separator
ButtonGroupSeparator divides controls. Outline buttons often read clearly without one; filled variants benefit from a separator.
<ButtonGroup> <Button variant="secondary" size="sm">Copy</Button> <ButtonGroupSeparator /> <Button variant="secondary" size="sm">Paste</Button></ButtonGroup>Split
Primary action plus a trailing icon action, separated by ButtonGroupSeparator.
<ButtonGroup> <Button variant="secondary">Button</Button> <ButtonGroupSeparator /> <IconButton variant="secondary" aria-label="Add"> <Plus /> </IconButton></ButtonGroup>Dropdown menu
Split Follow with a menu trigger—adapted from shadcn.
<ButtonGroup> <Button variant="outline">Follow</Button> <DropdownMenu> <DropdownMenuTrigger asChild> <IconButton variant="outline" aria-label="More options"> <CaretDown /> </IconButton> </DropdownMenuTrigger> <DropdownMenuContent align="end" className="w-44">{/* items */}</DropdownMenuContent> </DropdownMenu></ButtonGroup>Props
ButtonGroup
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" | Layout of child controls. |
className | string | — | Merged with buttonGroupVariants. |
Also accepts standard div attributes (role defaults to group via implementation).
ButtonGroupSeparator
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "horizontal" | "vertical" | "vertical" | Passed to underlying Separator. |
ButtonGroupText
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Merge props onto child via Slot. |