Installation

pnpm dlx shadcn@latest add @cortexcn/button-groupUsage
import { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants } from "@/components/button-group";Examples
Basic
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"export function ButtonGroupBasic() { return ( <div className="flex flex-col gap-6"> <div className="flex flex-col gap-4"> <ButtonGroup> <Button variant="outline">Button</Button> <Button variant="outline">Another Button</Button> </ButtonGroup> </div> </div> )}With input
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { Input } from "@/components/input"export function ButtonGroupWithInput() { return ( <div className="flex flex-col gap-6"> <div className="flex flex-col gap-4"> <ButtonGroup> <Button variant="outline">Button</Button> <Input placeholder="Type something here..." /> </ButtonGroup> <ButtonGroup> <Input placeholder="Type something here..." /> <Button variant="outline">Button</Button> </ButtonGroup> </div> </div> )}With text
import { Button } from "@/components/button"import { ButtonGroup, ButtonGroupText } from "@/components/button-group"import { Input } from "@/components/input"import { Label } from "@/components/label"export function ButtonGroupWithText() { return ( <div className="flex flex-col gap-6"> <div className="flex flex-col gap-4"> <ButtonGroup> <ButtonGroupText>Text</ButtonGroupText> <Button variant="outline">Another Button</Button> </ButtonGroup> <ButtonGroup> <ButtonGroupText asChild> <Label htmlFor="input-text">GPU Size</Label> </ButtonGroupText> <Input id="input-text" placeholder="Type something here..." className="style-luma:border-border" /> </ButtonGroup> </div> </div> )}With dropdown
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/dropdown-menu"import { AlertTriangleIcon, CheckIcon, ChevronDownIcon, CopyIcon, ShareIcon, TrashIcon, UserRoundXIcon, VolumeOffIcon } from "lucide-react"export function ButtonGroupWithDropdown() { return ( <div className="flex flex-col gap-6"> <div className="flex flex-col gap-4"> <ButtonGroup> <Button variant="outline">Update</Button> <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline" size="icon"> <ChevronDownIcon /> </Button> </DropdownMenuTrigger> <DropdownMenuContent align="end"> <DropdownMenuItem>Disable</DropdownMenuItem> <DropdownMenuItem variant="destructive"> Uninstall </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> </ButtonGroup> <ButtonGroup> <Button variant="outline">Follow</Button> <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline" size="icon"> <ChevronDownIcon /> </Button> </DropdownMenuTrigger> <DropdownMenuContent align="end" className="w-50"> <DropdownMenuGroup> <DropdownMenuItem> <VolumeOffIcon /> Mute Conversation </DropdownMenuItem> <DropdownMenuItem> <CheckIcon /> Mark as Read </DropdownMenuItem> <DropdownMenuItem> <AlertTriangleIcon /> Report Conversation </DropdownMenuItem> <DropdownMenuItem> <UserRoundXIcon /> Block User </DropdownMenuItem> <DropdownMenuItem> <ShareIcon /> Share Conversation </DropdownMenuItem> <DropdownMenuItem> <CopyIcon /> Copy Conversation </DropdownMenuItem> </DropdownMenuGroup> <DropdownMenuSeparator /> <DropdownMenuGroup> <DropdownMenuItem variant="destructive"> <TrashIcon /> Delete Conversation </DropdownMenuItem> </DropdownMenuGroup> </DropdownMenuContent> </DropdownMenu> </ButtonGroup> </div> </div> )}With select
import { useState } from "react"import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { Field } from "@/components/field"import { Input } from "@/components/input"import { Label } from "@/components/label"import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/select"import { ArrowRightIcon } from "lucide-react"export function ButtonGroupWithSelect() { const [currency, setCurrency] = useState("$") return ( <div className="flex flex-col gap-6"> <Field> <Label htmlFor="amount">Amount</Label> <ButtonGroup> <Select value={currency} onValueChange={setCurrency}> <SelectTrigger> <SelectValue /> </SelectTrigger> <SelectContent align="start"> <SelectGroup> <SelectItem value="$">$</SelectItem> <SelectItem value="€">€</SelectItem> <SelectItem value="£">£</SelectItem> </SelectGroup> </SelectContent> </Select> <Input placeholder="Enter amount to send" /> <Button variant="outline"> <ArrowRightIcon /> </Button> </ButtonGroup> </Field> </div> )}With icons
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { FlipHorizontalIcon, FlipVerticalIcon, RotateCwIcon } from "lucide-react"export function ButtonGroupWithIcons() { return ( <div className="flex flex-col gap-6"> <div className="flex flex-col gap-4"> <ButtonGroup> <Button variant="outline"> <FlipHorizontalIcon /> </Button> <Button variant="outline"> <FlipVerticalIcon /> </Button> <Button variant="outline"> <RotateCwIcon /> </Button> </ButtonGroup> </div> </div> )}With input group
import { Input } from "@/components/input"import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/input-group"import { SearchIcon } from "lucide-react"export function ButtonGroupWithInputGroup() { return ( <div className="flex flex-col gap-6"> <div className="flex flex-col gap-4"> <InputGroup> <InputGroupInput placeholder="Type to search..." /> <InputGroupAddon align="inline-start" className="text-muted-foreground" > <SearchIcon /> </InputGroupAddon> </InputGroup> </div> </div> )}With fields
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { Field, FieldGroup } from "@/components/field"import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/input-group"import { Label } from "@/components/label"import { MinusIcon, PlusIcon } from "lucide-react"export function ButtonGroupWithFields() { return ( <div className="flex flex-col gap-6"> <FieldGroup className="grid grid-cols-3 gap-4"> <Field className="col-span-2"> <Label htmlFor="width">Width</Label> <ButtonGroup> <InputGroup> <InputGroupInput id="width" /> <InputGroupAddon className="text-muted-foreground"> W </InputGroupAddon> <InputGroupAddon align="inline-end" className="text-muted-foreground" > px </InputGroupAddon> </InputGroup> <Button variant="outline" size="icon"> <MinusIcon /> </Button> <Button variant="outline" size="icon"> <PlusIcon /> </Button> </ButtonGroup> </Field> </FieldGroup> </div> )}With like
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { HeartIcon } from "lucide-react"export function ButtonGroupWithLike() { return ( <div className="flex flex-col gap-6"> <ButtonGroup> <Button variant="outline"> <HeartIcon data-icon="inline-start" />{" "} Like </Button> <Button variant="outline" asChild size="icon" className="w-12"> <span>1.2K</span> </Button> </ButtonGroup> </div> )}With select and input
import { ButtonGroup } from "@/components/button-group"import { Input } from "@/components/input"import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/select"export function ButtonGroupWithSelectAndInput() { return ( <div className="flex flex-col gap-6"> <ButtonGroup> <Select defaultValue="hours"> <SelectTrigger id="duration"> <SelectValue placeholder="Select duration" /> </SelectTrigger> <SelectContent align="start"> <SelectGroup> <SelectItem value="hours">Hours</SelectItem> <SelectItem value="days">Days</SelectItem> <SelectItem value="weeks">Weeks</SelectItem> </SelectGroup> </SelectContent> </Select> <Input /> </ButtonGroup> </div> )}Nested
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { InputGroup, InputGroupAddon, InputGroupInput } from "@/components/input-group"import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/tooltip"import { AudioLinesIcon, PlusIcon } from "lucide-react"export function ButtonGroupNested() { return ( <div className="flex flex-col gap-6"> <ButtonGroup> <ButtonGroup> <Button variant="outline" size="icon"> <PlusIcon /> </Button> </ButtonGroup> <ButtonGroup> <InputGroup> <InputGroupInput placeholder="Send a message..." /> <Tooltip> <TooltipTrigger asChild> <InputGroupAddon align="inline-end"> <AudioLinesIcon /> </InputGroupAddon> </TooltipTrigger> <TooltipContent>Voice Mode</TooltipContent> </Tooltip> </InputGroup> </ButtonGroup> </ButtonGroup> </div> )}Pagination
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react"export function ButtonGroupPagination() { return ( <div className="flex flex-col gap-6"> <ButtonGroup> <Button variant="outline" size="sm"> <ArrowLeftIcon data-icon="inline-start" /> Previous </Button> <Button variant="outline" size="sm"> 1 </Button> <Button variant="outline" size="sm"> 2 </Button> <Button variant="outline" size="sm"> 3 </Button> <Button variant="outline" size="sm"> 4 </Button> <Button variant="outline" size="sm"> 5 </Button> <Button variant="outline" size="sm"> Next <ArrowRightIcon data-icon="inline-end" /> </Button> </ButtonGroup> </div> )}Pagination split
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react"export function ButtonGroupPaginationSplit() { return ( <div className="flex flex-col gap-6"> <ButtonGroup> <ButtonGroup> <Button variant="outline" size="sm"> 1 </Button> <Button variant="outline" size="sm"> 2 </Button> <Button variant="outline" size="sm"> 3 </Button> <Button variant="outline" size="sm"> 4 </Button> <Button variant="outline" size="sm"> 5 </Button> </ButtonGroup> <ButtonGroup> <Button variant="outline" size="icon-xs"> <ArrowLeftIcon /> </Button> <Button variant="outline" size="icon-xs"> <ArrowRightIcon /> </Button> </ButtonGroup> </ButtonGroup> </div> )}Navigation
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react"export function ButtonGroupNavigation() { return ( <div className="flex flex-col gap-6"> <ButtonGroup> <ButtonGroup> <Button variant="outline"> <ArrowLeftIcon /> </Button> <Button variant="outline"> <ArrowRightIcon /> </Button> </ButtonGroup> <ButtonGroup aria-label="Single navigation button"> <Button variant="outline" size="icon"> <ArrowLeftIcon /> </Button> </ButtonGroup> </ButtonGroup> </div> )}Text alignment
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { Field } from "@/components/field"import { Label } from "@/components/label"export function ButtonGroupTextAlignment() { return ( <div className="flex flex-col gap-6"> <Field> <Label id="alignment-label">Text Alignment</Label> <ButtonGroup aria-labelledby="alignment-label"> <Button variant="outline" size="sm"> Left </Button> <Button variant="outline" size="sm"> Center </Button> <Button variant="outline" size="sm"> Right </Button> <Button variant="outline" size="sm"> Justify </Button> </ButtonGroup> </Field> </div> )}Vertical
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { MinusIcon, PlusIcon } from "lucide-react"export function ButtonGroupVertical() { return ( <div className="flex flex-col gap-6"> <div className="flex gap-6"> <ButtonGroup orientation="vertical" aria-label="Media controls" className="h-fit" > <Button variant="outline" size="icon"> <PlusIcon /> </Button> <Button variant="outline" size="icon"> <MinusIcon /> </Button> </ButtonGroup> </div> </div> )}Vertical nested
import { Button } from "@/components/button"import { ButtonGroup } from "@/components/button-group"import { CopyIcon, FlipHorizontalIcon, FlipVerticalIcon, RotateCwIcon, SearchIcon, ShareIcon, TrashIcon } from "lucide-react"export function ButtonGroupVerticalNested() { return ( <div className="flex flex-col gap-6"> <ButtonGroup orientation="vertical" aria-label="Design tools palette"> <ButtonGroup orientation="vertical"> <Button variant="outline" size="icon"> <SearchIcon /> </Button> <Button variant="outline" size="icon"> <CopyIcon /> </Button> <Button variant="outline" size="icon"> <ShareIcon /> </Button> </ButtonGroup> <ButtonGroup orientation="vertical"> <Button variant="outline" size="icon"> <FlipHorizontalIcon /> </Button> <Button variant="outline" size="icon"> <FlipVerticalIcon /> </Button> <Button variant="outline" size="icon"> <RotateCwIcon /> </Button> </ButtonGroup> <ButtonGroup> <Button variant="outline" size="icon"> <TrashIcon /> </Button> </ButtonGroup> </ButtonGroup> </div> )}Adapted from the shadcn/ui Button Group (MIT).
