Group related buttons together with consistent styling and spacing
Import
import { ButtonGroup, Button } from "heroui-solid";Usage
import {
ChevronDown,
ChevronLeft,
ChevronRight,
CodeFork,
Ellipsis,
Picture,
Pin,
QrCode,
Star,
TextAlignCenter,
TextAlignJustify,
TextAlignLeft,
TextAlignRight,
ThumbsDown,
ThumbsUp,
Video
} from "gravity-icons-solid"
import {
Button,
ButtonGroup,
Chip,
Description,
Dropdown,
Label
} from "heroui-solid"
export function Basic() {
return (
<div class="flex flex-col items-start gap-6">
{/* Single button with dropdown */}
<div class="flex flex-col gap-2">
<ButtonGroup>
<Button>Merge pull request</Button>
<Dropdown>
<Button isIconOnly aria-label="More options">
<ButtonGroup.Separator />
<ChevronDown />
</Button>
<Dropdown.Popover class="max-w-[290px]" placement="bottom-end">
<Dropdown.Menu>
<Dropdown.Item
class="flex flex-col items-start gap-1"
id="merge"
textValue="Create a merge commit"
>
<Label>Create a merge commit</Label>
<Description>
All commits from this branch will be added to the base
branch
</Description>
</Dropdown.Item>
<Dropdown.Item
class="flex flex-col items-start gap-1"
id="squash-and-merge"
textValue="Squash and merge"
>
<Label>Squash and merge</Label>
<Description>
The 14 commits from this branch will be combined into one
commit in the base branch
</Description>
</Dropdown.Item>
<Dropdown.Item
class="flex flex-col items-start gap-1"
id="rebase-and-merge"
textValue="Rebase and merge"
>
<Label>Rebase and merge</Label>
<Description>
The 14 commits from this branch will be rebased and added to
the base branch
</Description>
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown.Popover>
</Dropdown>
</ButtonGroup>
</div>
{/* Individual buttons */}
<div class="flex flex-col gap-2">
<div class="flex flex-wrap gap-x-2 gap-y-4">
<ButtonGroup variant="tertiary">
<Button>
<CodeFork class="size-3.5" />
Fork
<Chip color="accent" size="sm" variant="soft">
24
</Chip>
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<ChevronDown />
</Button>
</ButtonGroup>
<ButtonGroup variant="tertiary">
<Button isIconOnly>
<QrCode />
</Button>
<Button>
<ButtonGroup.Separator />
Scan to pay
</Button>
</ButtonGroup>
<ButtonGroup variant="tertiary">
<Button>
<ThumbsUp />
<span class="text-xs font-semibold">2.4K</span>
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<ThumbsDown />
</Button>
</ButtonGroup>
<ButtonGroup variant="tertiary">
<Button>
<Star class="size-3.5" />
Star
</Button>
<Button class="px-2">
<ButtonGroup.Separator />
<Chip color="accent" size="sm" variant="soft">
104
</Chip>
</Button>
</ButtonGroup>
<ButtonGroup variant="tertiary">
<Button>
<Pin />
Pinned
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<ChevronDown />
</Button>
</ButtonGroup>
</div>
</div>
{/* Previous/Next Button Group */}
<div class="flex flex-col gap-2">
<ButtonGroup variant="tertiary">
<Button>
<ChevronLeft />
Previous
</Button>
<Button>
<ButtonGroup.Separator />
Next
<ChevronRight />
</Button>
</ButtonGroup>
</div>
{/* Content Selection Button Group */}
<div class="flex flex-col gap-2">
<ButtonGroup variant="tertiary">
<Button>
<Picture />
Photos
</Button>
<Button>
<ButtonGroup.Separator />
<Video />
Videos
</Button>
<Button isIconOnly aria-label="More options">
<ButtonGroup.Separator />
<Ellipsis />
</Button>
</ButtonGroup>
</div>
{/* Text Alignment Button Group */}
<div class="flex flex-col gap-2">
<ButtonGroup variant="tertiary">
<Button>Left</Button>
<Button>
<ButtonGroup.Separator />
Center
</Button>
<Button>
<ButtonGroup.Separator />
Right
</Button>
</ButtonGroup>
</div>
{/* Icon-Only Alignment Button Group */}
<div class="flex flex-col gap-2">
<ButtonGroup variant="tertiary">
<Button isIconOnly>
<TextAlignLeft />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TextAlignCenter />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TextAlignRight />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TextAlignJustify />
</Button>
</ButtonGroup>
</div>
</div>
)
}Anatomy
Import the ButtonGroup component and access all parts using dot notation.
import { ButtonGroup, Button } from "heroui-solid";
export default () => (
<ButtonGroup>
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
);ButtonGroup wraps multiple Button components together, applying consistent styling, spacing, and automatic border radius handling. It uses context to pass
size,variant, andisDisabledprops to all child buttons.
Variants
Primary
Secondary
Tertiary
Outline
Ghost
Danger
import { Button, ButtonGroup } from "heroui-solid"
export function Variants() {
return (
<div class="flex flex-col gap-6">
<div class="flex flex-col gap-2">
<p class="text-sm text-muted">Primary</p>
<ButtonGroup variant="primary">
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm text-muted">Secondary</p>
<ButtonGroup variant="secondary">
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm text-muted">Tertiary</p>
<ButtonGroup variant="tertiary">
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm text-muted">Outline</p>
<ButtonGroup variant="outline">
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm text-muted">Ghost</p>
<ButtonGroup variant="ghost">
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
</div>
<div class="flex flex-col gap-2">
<p class="text-sm text-muted">Danger</p>
<ButtonGroup variant="danger">
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
</div>
</div>
)
}Sizes
Small
Medium (default)
Large
import { Button, ButtonGroup } from "heroui-solid"
export function Sizes() {
return (
<div class="flex flex-col gap-4">
<div class="flex flex-col items-start gap-2">
<p class="text-sm text-muted">Small</p>
<ButtonGroup size="sm" variant="secondary">
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
</div>
<div class="flex flex-col items-start gap-2">
<p class="text-sm text-muted">Medium (default)</p>
<ButtonGroup size="md" variant="secondary">
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
</div>
<div class="flex flex-col items-start gap-2">
<p class="text-sm text-muted">Large</p>
<ButtonGroup size="lg" variant="secondary">
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
</div>
</div>
)
}Orientation
Use the orientation prop to arrange buttons horizontally or vertically.
import {
TextAlignCenter,
TextAlignJustify,
TextAlignLeft,
TextAlignRight
} from "gravity-icons-solid"
import { Button, ButtonGroup } from "heroui-solid"
export function Orientation() {
return (
<div class="flex items-start gap-8">
<div class="flex flex-col gap-2">
<span class="text-sm text-muted">Horizontal</span>
<ButtonGroup orientation="horizontal" variant="tertiary">
<Button isIconOnly>
<TextAlignLeft />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TextAlignCenter />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TextAlignRight />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TextAlignJustify />
</Button>
</ButtonGroup>
</div>
<div class="flex flex-col gap-2">
<span class="text-sm text-muted">Vertical</span>
<ButtonGroup orientation="vertical" variant="tertiary">
<Button isIconOnly>
<TextAlignLeft />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TextAlignCenter />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TextAlignRight />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TextAlignJustify />
</Button>
</ButtonGroup>
</div>
</div>
)
}With Icons
With icons
Icon only buttons
import { Globe, Plus, TrashBin } from "gravity-icons-solid"
import { Button, ButtonGroup } from "heroui-solid"
export function WithIcons() {
return (
<div class="flex flex-col gap-6">
<div class="flex flex-col items-start gap-2">
<p class="text-sm text-muted">With icons</p>
<ButtonGroup variant="secondary">
<Button>
<Globe />
Search
</Button>
<Button>
<ButtonGroup.Separator />
<Plus />
Add
</Button>
<Button>
<ButtonGroup.Separator />
<TrashBin />
Delete
</Button>
</ButtonGroup>
</div>
<div class="flex flex-col items-start gap-2">
<p class="text-sm text-muted">Icon only buttons</p>
<ButtonGroup variant="tertiary">
<Button isIconOnly>
<Globe />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<Plus />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TrashBin />
</Button>
</ButtonGroup>
</div>
</div>
)
}Full Width
import {
TextAlignCenter,
TextAlignLeft,
TextAlignRight
} from "gravity-icons-solid"
import { Button, ButtonGroup } from "heroui-solid"
export function FullWidth() {
return (
<div class="w-[400px] space-y-3">
<ButtonGroup fullWidth>
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
<ButtonGroup fullWidth>
<Button isIconOnly>
<TextAlignLeft />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TextAlignCenter />
</Button>
<Button isIconOnly>
<ButtonGroup.Separator />
<TextAlignRight />
</Button>
</ButtonGroup>
</div>
)
}Disabled State
All buttons disabled
Group disabled, but one button overrides
import { Button, ButtonGroup } from "heroui-solid"
export function Disabled() {
return (
<div class="flex flex-col gap-6">
<div class="flex flex-col items-start gap-2">
<p class="text-sm text-muted">All buttons disabled</p>
<ButtonGroup isDisabled>
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
</div>
<div class="flex flex-col items-start gap-2">
<p class="text-sm text-muted">
Group disabled, but one button overrides
</p>
<ButtonGroup isDisabled>
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button isDisabled={false}>
<ButtonGroup.Separator />
Third (enabled)
</Button>
</ButtonGroup>
</div>
</div>
)
}Without Separator
Simply omit the <ButtonGroup.Separator /> component from your buttons.
import { Button, ButtonGroup } from "heroui-solid"
export function WithoutSeparator() {
return (
<ButtonGroup>
<Button>First</Button>
<Button>Second</Button>
<Button>Third</Button>
</ButtonGroup>
)
}Styling
Passing Tailwind CSS classes
import { ButtonGroup, Button } from "heroui-solid";
function CustomButtonGroup() {
return (
<ButtonGroup class="gap-2">
<Button>First</Button>
<Button>
<ButtonGroup.Separator />
Second
</Button>
<Button>
<ButtonGroup.Separator />
Third
</Button>
</ButtonGroup>
);
}Customizing the component classes
To customize the ButtonGroup component classes, you can use the @layer components directive.
Learn more.
@layer components {
.button-group {
@apply gap-2 rounded-lg;
}
.button-group__separator {
@apply opacity-25;
}
}HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.
CSS Classes
The ButtonGroup component uses these CSS classes (View source styles):
Base Classes
.button-group- Base button group container.button-group--full-width- Full width modifier.button-group__separator- Separator element between buttons
The ButtonGroup component automatically applies border radius to buttons:
- First button gets rounded left/start edge
- Last button gets rounded right/end edge
- Middle buttons have no border radius
- Single button gets full border radius on all edges
Add <ButtonGroup.Separator /> inside each Button (except the first) to show dividers between buttons.
API Reference
ButtonGroup Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'tertiary' | 'outline' | 'ghost' | 'danger' | - | Visual style variant applied to all buttons in the group |
size | 'sm' | 'md' | 'lg' | - | Size applied to all buttons in the group |
orientation | 'horizontal' | 'vertical' | 'horizontal' | The orientation of the button group |
fullWidth | boolean | false | Whether the button group should take full width of its container |
isDisabled | boolean | false | Whether all buttons in the group are disabled (can be overridden on individual buttons) |
class | string | - | Additional CSS classes |
children | JSX.Element | - | Button components to group together |
ButtonGroup.Separator Props
| Prop | Type | Default | Description |
|---|---|---|---|
class | string | - | Additional CSS classes |
Notes
- ButtonGroup uses context to pass
size,variant, andisDisabledprops to child Button components. Unlike HeroUI React, which tags only direct children, the Solid port propagates these values to every Button descendant through context — in practice buttons are direct children of the group, so the result is the same. - Individual Button components can override the group's
isDisabledprop by settingisDisabled={false} - The component automatically handles border radius between buttons
- Add
<ButtonGroup.Separator />inside each Button (except the first) to show dividers between buttons - Buttons in a group have their active/pressed scale transform removed for a more cohesive appearance
Last updated: 7/19/26, 3:27 AM