Components

Button Group

A container that groups related buttons together with consistent styling.

Installation

Cortexcn
pnpm dlx shadcn@latest add @cortexcn/button-group

Usage

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

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

W
px
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

1.2K
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>  )}
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).