Button Group
Buttons joined into one segmented control — horizontal, vertical or split.
import { Button } from '@/components/ui/button'
import { ButtonGroup, ButtonGroupSeparator } from '@/components/ui/button-group'
export default function ButtonGroupDemo() {
return (
<div className="flex flex-wrap items-center justify-center gap-6">
<ButtonGroup>
<Button variant="outline">Archive</Button>
<Button variant="outline">Report</Button>
<Button variant="outline">Snooze</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="secondary">Save</Button>
<ButtonGroupSeparator />
<Button variant="secondary">Save as…</Button>
</ButtonGroup>
</div>
)
}
Installation
pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/button-group.jsonNeeds a React + Tailwind project set up with shadcn. Copies the component source straight into your project, so you can edit it.
Button Group imports cn() from lib/utils.ts — add it too if you don't have it yet:
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Usage
import { ButtonGroup, ButtonGroupSeparator, ButtonGroupText } from '@/components/ui/button-group'
import { Button } from '@/components/ui/button'
<ButtonGroup>
<Button variant="outline">Left</Button>
<Button variant="outline">Middle</Button>
<Button variant="outline">Right</Button>
</ButtonGroup>Examples
Vertical
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
export default function ButtonGroupVertical() {
return (
<div className="flex items-center gap-6">
<ButtonGroup orientation="vertical" aria-label="Zoom controls">
<Button variant="outline" size="icon" aria-label="Zoom in">
<PlusIcon />
</Button>
<Button variant="outline" size="icon" aria-label="Zoom out">
<MinusIcon />
</Button>
</ButtonGroup>
<ButtonGroup orientation="vertical" aria-label="View">
<Button variant="outline">Day</Button>
<Button variant="outline">Week</Button>
<Button variant="outline">Month</Button>
</ButtonGroup>
</div>
)
}
function PlusIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round">
<path d="M5 12h14M12 5v14" />
</svg>
)
}
function MinusIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round">
<path d="M5 12h14" />
</svg>
)
}
Split button
import { Button } from '@/components/ui/button'
import { ButtonGroup, ButtonGroupSeparator } from '@/components/ui/button-group'
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
} from '@/components/ui/dropdown-menu'
/** A split button: the main action, and a menu of alternatives beside it. */
export default function ButtonGroupSplit() {
return (
<ButtonGroup>
<Button variant="secondary">Publish</Button>
<ButtonGroupSeparator />
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button variant="secondary" size="icon" aria-label="More publish options">
<ChevronDownIcon />
</Button>
}
/>
<DropdownMenuContent align="end" className="min-w-44">
<DropdownMenuItem>Publish now</DropdownMenuItem>
<DropdownMenuItem>Schedule…</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>Save as draft</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</ButtonGroup>
)
}
function ChevronDownIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round">
<path d="m6 9 6 6 6-6" />
</svg>
)
}
API Reference
| Name | Type | Default | Description |
|---|---|---|---|
| ButtonGroup orientation | 'horizontal' | 'vertical' | 'horizontal' | Direction of the group. Only the outer corners stay rounded. |
| ButtonGroupSeparator | component | — | A divider between buttons that share a fill (default, secondary); outline buttons already have a border. |
| ButtonGroupText | component | — | A non-interactive label attached to the group, such as a count. |