import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { ButtonGroup } from "@/components/ui/button-group";
export default function ButtonGroupBasic() {
return (
<div className="flex flex-wrap items-center gap-3">
<ButtonGroup aria-label="Message actions">
<Button variant="secondary">Archive</Button>
<Button variant="secondary">Report</Button>
<Button variant="secondary">Snooze</Button>
</ButtonGroup>
<ButtonGroup aria-label="Pagination">
<Button variant="outline" size="icon" aria-label="Previous">
<ArrowLeftIcon />
</Button>
<Button variant="outline" size="icon" aria-label="Next">
<ArrowRightIcon />
</Button>
</ButtonGroup>
</div>
);
}- Add the registryOnce per project
pnpm dlx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json - Add button-group
pnpm dlx shadcn@latest add @jarvis/button-group
Usage
import { Button } from "@/components/ui/button";
import { ButtonGroup } from "@/components/ui/button-group";
export function MessageActions() {
return (
<ButtonGroup aria-label="Message actions">
<Button variant="secondary">Archive</Button>
<Button variant="secondary">Report</Button>
<Button variant="secondary">Snooze</Button>
</ButtonGroup>
);
}The group has the group role. Give it an aria-label when its purpose isn't clear from the
buttons alone.
Composition
Examples
With text
ButtonGroupText adds a label or count beside the buttons. For text attached to an input, use
Input Group.
Range
1.2k
import { CalendarDaysIcon, StarIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { ButtonGroup, ButtonGroupText } from "@/components/ui/button-group";
export default function ButtonGroupWithText() {
return (
<div className="flex flex-wrap items-center gap-3">
<ButtonGroup>
<ButtonGroupText>
<CalendarDaysIcon />
Range
</ButtonGroupText>
<Button variant="secondary">Last 30 days</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="secondary">
<StarIcon />
Star
</Button>
<ButtonGroupText>1.2k</ButtonGroupText>
</ButtonGroup>
</div>
);
}Split button
ButtonGroupSeparator divides a main action from a menu of related ones.
import { ArchiveIcon, ChevronDownIcon, EllipsisIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { ButtonGroup, ButtonGroupSeparator } from "@/components/ui/button-group";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export default function ButtonGroupSplitButton() {
return (
<div className="flex flex-wrap items-center gap-3">
<ButtonGroup>
<Button variant="primary">Publish</Button>
<ButtonGroupSeparator />
<DropdownMenu>
<DropdownMenuTrigger
render={<Button variant="primary" size="icon" aria-label="More publish options" />}
>
<ChevronDownIcon />
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>Schedule for later</DropdownMenuItem>
<DropdownMenuItem>Save as draft</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</ButtonGroup>
<ButtonGroup>
<Button variant="secondary">
<ArchiveIcon />
Archive
</Button>
<ButtonGroupSeparator />
<Button variant="secondary" size="icon" aria-label="More options">
<EllipsisIcon />
</Button>
</ButtonGroup>
</div>
);
}Nested
Nest groups to space out sets of buttons.
import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { ButtonGroup } from "@/components/ui/button-group";
export default function ButtonGroupNested() {
return (
<ButtonGroup aria-label="Pagination">
<ButtonGroup>
<Button variant="secondary" size="sm">
1
</Button>
<Button variant="secondary" size="sm">
2
</Button>
<Button variant="secondary" size="sm">
3
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="secondary" size="icon-sm" aria-label="Previous page">
<ArrowLeftIcon />
</Button>
<Button variant="secondary" size="icon-sm" aria-label="Next page">
<ArrowRightIcon />
</Button>
</ButtonGroup>
</ButtonGroup>
);
}Vertical
Set orientation="vertical" to stack the buttons.
import { MinusIcon, PlusIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { ButtonGroup } from "@/components/ui/button-group";
export default function ButtonGroupVertical() {
return (
<ButtonGroup orientation="vertical" aria-label="Zoom">
<Button variant="secondary" size="icon" aria-label="Zoom in">
<PlusIcon />
</Button>
<Button variant="secondary" size="icon" aria-label="Zoom out">
<MinusIcon />
</Button>
</ButtonGroup>
);
}Props
ButtonGroupText can render a <label> instead of a <div> with render.
| Part | Extends |
|---|---|
| ButtonGroup | <div> |
| ButtonGroupText | <div> |
| ButtonGroupSeparator | Separator |
The tables leave out className, style and render. Parts built on Base UI take them as its styling and composition guides describe.
ButtonGroup
| Prop | Type | Default |
|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" |
ButtonGroupSeparator
| Prop | Type | Default |
|---|---|---|
orientationThe orientation of the separator. | "horizontal" | "vertical" | "vertical" |