Skip to content

ButtonGroup

A container that groups related buttons together with consistent styling.

Code
import {
ArchiveIcon,
ArrowLeftIcon,
Button,
ButtonGroup,
CalendarPlusIcon,
ClockIcon,
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
ListFilterIcon,
MailCheckIcon,
MoreHorizontalIcon,
TagIcon,
Trash2Icon,
} from "@falcon/ui-kit";
import { useState } from "react";
export function Example() {
const [status, setStatus] = useState("open");
return (
<ButtonGroup>
<ButtonGroup className="tw:hidden tw:sm:flex">
<Button variant="outline" size="icon" aria-label="Go Back">
<ArrowLeftIcon />
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline">Archive</Button>
<Button variant="outline">Report</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline">Snooze</Button>
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button variant="outline" size="icon" aria-label="More Options" />
}
>
<MoreHorizontalIcon />
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="tw:w-40">
<DropdownMenuGroup>
<DropdownMenuItem>
<MailCheckIcon />
Mark as reviewed
</DropdownMenuItem>
<DropdownMenuItem>
<ArchiveIcon />
Archive
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<ClockIcon />
Snooze
</DropdownMenuItem>
<DropdownMenuItem>
<CalendarPlusIcon />
Schedule follow-up
</DropdownMenuItem>
<DropdownMenuItem>
<ListFilterIcon />
Add to queue
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<TagIcon />
Set status
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuRadioGroup
value={status}
onValueChange={setStatus}
>
<DropdownMenuRadioItem value="open">
Open
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="on-hold">
On hold
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="closed">
Closed
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuSubContent>
</DropdownMenuSub>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">
<Trash2Icon />
Delete order
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</ButtonGroup>
</ButtonGroup>
);
}

Use the following composition to build a ButtonGroup:

ButtonGroup
├── Button or Input
└── ButtonGroupSeparator
  • The ButtonGroup component has the role attribute set to group.
  • Use Tab to navigate between the buttons in the group.
  • Use aria-label or aria-labelledby to label the button group.
<ButtonGroup aria-label="Button group">
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>

Set the orientation prop to change the button group layout.

Code
import { Button, ButtonGroup, MinusIcon, PlusIcon } from "@falcon/ui-kit";
export function Example() {
return (
<ButtonGroup
orientation="vertical"
aria-label="Media controls"
className="tw:h-fit"
>
<Button variant="outline" size="icon" aria-label="Increase">
<PlusIcon />
</Button>
<Button variant="outline" size="icon" aria-label="Decrease">
<MinusIcon />
</Button>
</ButtonGroup>
);
}

Control the size of buttons using the size prop on individual buttons.

Code
import { Button, ButtonGroup, PlusIcon } from "@falcon/ui-kit";
export function Example() {
return (
<div className="tw:flex tw:flex-col tw:items-start tw:gap-8">
<ButtonGroup>
<Button variant="outline" size="sm">
Small
</Button>
<Button variant="outline" size="sm">
Button
</Button>
<Button variant="outline" size="sm">
Group
</Button>
<Button variant="outline" size="icon-sm" aria-label="Add">
<PlusIcon />
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline">Default</Button>
<Button variant="outline">Button</Button>
<Button variant="outline">Group</Button>
<Button variant="outline" size="icon" aria-label="Add">
<PlusIcon />
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="outline" size="lg">
Large
</Button>
<Button variant="outline" size="lg">
Button
</Button>
<Button variant="outline" size="lg">
Group
</Button>
<Button variant="outline" size="icon-lg" aria-label="Add">
<PlusIcon />
</Button>
</ButtonGroup>
</div>
);
}

Nest <ButtonGroup> components to create button groups with spacing.

Code
import {
AudioLinesIcon,
Button,
ButtonGroup,
InputGroup,
InputGroupAddon,
InputGroupInput,
PlusIcon,
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@falcon/ui-kit";
export function Example() {
return (
<ButtonGroup>
<ButtonGroup>
<Button variant="outline" size="icon" aria-label="Add">
<PlusIcon />
</Button>
</ButtonGroup>
<ButtonGroup>
<InputGroup>
<InputGroupInput placeholder="Send a message..." />
<Tooltip>
<TooltipTrigger render={<InputGroupAddon align="inline-end" />}>
<AudioLinesIcon />
</TooltipTrigger>
<TooltipContent>Voice Mode</TooltipContent>
</Tooltip>
</InputGroup>
</ButtonGroup>
</ButtonGroup>
);
}

The ButtonGroupSeparator component visually divides buttons within a group.

Buttons with variant outline do not need a separator since they have a border. For other variants, a separator is recommended to improve the visual hierarchy.

Code
import { Button, ButtonGroup, ButtonGroupSeparator } from "@falcon/ui-kit";
export function Example() {
return (
<ButtonGroup>
<Button variant="secondary" size="sm">
Copy
</Button>
<ButtonGroupSeparator />
<Button variant="secondary" size="sm">
Paste
</Button>
</ButtonGroup>
);
}

Create a split button group by adding two buttons separated by a ButtonGroupSeparator.

Code
import {
Button,
ButtonGroup,
ButtonGroupSeparator,
PlusIcon,
} from "@falcon/ui-kit";
export function Example() {
return (
<ButtonGroup>
<Button variant="secondary">Button</Button>
<ButtonGroupSeparator />
<Button size="icon" variant="secondary" aria-label="Add">
<PlusIcon />
</Button>
</ButtonGroup>
);
}

Wrap an Input component with buttons.

Code
import { Button, ButtonGroup, Input, SearchIcon } from "@falcon/ui-kit";
export function Example() {
return (
<ButtonGroup>
<Input placeholder="Search..." />
<Button variant="outline" aria-label="Search">
<SearchIcon />
</Button>
</ButtonGroup>
);
}

Wrap an InputGroup component to create complex input layouts.

Code
import {
AudioLinesIcon,
Button,
ButtonGroup,
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
PlusIcon,
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@falcon/ui-kit";
import { useState } from "react";
export function Example() {
const [voiceEnabled, setVoiceEnabled] = useState(false);
return (
<ButtonGroup>
<ButtonGroup>
<Button variant="outline" size="icon" aria-label="Add">
<PlusIcon />
</Button>
</ButtonGroup>
<ButtonGroup>
<InputGroup>
<InputGroupInput
placeholder={
voiceEnabled ? "Record and send audio..." : "Send a message..."
}
disabled={voiceEnabled}
/>
<InputGroupAddon align="inline-end">
<Tooltip>
<TooltipTrigger
render={
<InputGroupButton
onClick={() => setVoiceEnabled(!voiceEnabled)}
size="icon-xs"
data-active={voiceEnabled}
className="tw:data-[active=true]:bg-primary/10 tw:data-[active=true]:text-primary"
aria-pressed={voiceEnabled}
/>
}
>
<AudioLinesIcon />
</TooltipTrigger>
<TooltipContent>Voice Mode</TooltipContent>
</Tooltip>
</InputGroupAddon>
</InputGroup>
</ButtonGroup>
</ButtonGroup>
);
}

Create a split button group with a DropdownMenu component.

Code
import {
AlertTriangleIcon,
Button,
ButtonGroup,
CheckIcon,
ChevronDownIcon,
CopyIcon,
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
ShareIcon,
TrashIcon,
UserRoundXIcon,
VolumeOffIcon,
} from "@falcon/ui-kit";
export function Example() {
return (
<ButtonGroup>
<Button variant="outline">Follow</Button>
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button
variant="outline"
className="tw:pl-2!"
aria-label="More Options"
/>
}
>
<ChevronDownIcon />
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="tw:w-44">
<DropdownMenuGroup>
<DropdownMenuItem>
<VolumeOffIcon />
Mute notifications
</DropdownMenuItem>
<DropdownMenuItem>
<CheckIcon />
Mark as reviewed
</DropdownMenuItem>
<DropdownMenuItem>
<AlertTriangleIcon />
Report issue
</DropdownMenuItem>
<DropdownMenuItem>
<UserRoundXIcon />
Remove contact
</DropdownMenuItem>
<DropdownMenuItem>
<ShareIcon />
Share account
</DropdownMenuItem>
<DropdownMenuItem>
<CopyIcon />
Copy account link
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">
<TrashIcon />
Delete account
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</ButtonGroup>
);
}

Pair with a Select component.

Code
import {
ArrowRightIcon,
Button,
ButtonGroup,
Input,
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
} from "@falcon/ui-kit";
import { useState } from "react";
const UNITS = [
{ label: "Gallons", value: "gal" },
{ label: "Pounds", value: "lb" },
{ label: "Tons", value: "ton" },
];
export function Example() {
const [unit, setUnit] = useState<string | null>("gal");
return (
<ButtonGroup>
<ButtonGroup>
<Select
items={UNITS}
value={unit}
onValueChange={(value) => setUnit(value)}
>
<SelectTrigger className="tw:font-mono">{unit}</SelectTrigger>
<SelectContent alignItemWithTrigger={false} align="start">
<SelectGroup>
{UNITS.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.value}{" "}
<span className="tw:text-muted-foreground">{item.label}</span>
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<Input placeholder="10.00" pattern="[0-9]*" />
</ButtonGroup>
<ButtonGroup>
<Button aria-label="Send" size="icon" variant="outline">
<ArrowRightIcon />
</Button>
</ButtonGroup>
</ButtonGroup>
);
}

Use with a Popover component.

Code
import {
BotIcon,
Button,
ButtonGroup,
ChevronDownIcon,
Field,
FieldDescription,
FieldLabel,
Popover,
PopoverContent,
PopoverDescription,
PopoverHeader,
PopoverTitle,
PopoverTrigger,
Textarea,
} from "@falcon/ui-kit";
export function Example() {
return (
<ButtonGroup>
<Button variant="outline">
<BotIcon /> Assistant
</Button>
<Popover>
<PopoverTrigger
render={
<Button variant="outline" size="icon" aria-label="Open Popover" />
}
>
<ChevronDownIcon />
</PopoverTrigger>
<PopoverContent align="end" className="tw:rounded-xl tw:text-sm">
<PopoverHeader>
<PopoverTitle>Start a new task</PopoverTitle>
<PopoverDescription>
Describe your task in natural language.
</PopoverDescription>
</PopoverHeader>
<Field>
<FieldLabel htmlFor="task" className="tw:sr-only">
Task Description
</FieldLabel>
<Textarea
id="task"
placeholder="I need to..."
className="tw:resize-none"
/>
<FieldDescription>
The assistant will draft an order for review.
</FieldDescription>
</Field>
</PopoverContent>
</Popover>
</ButtonGroup>
);
}

Groups related peer actions. Renders a <div> element with role="group" and accepts standard <div> props.

orientation?: "horizontal" | "vertical" | null = "horizontal"

Controls whether the group’s actions are arranged in a row or column.

Separates adjacent actions in a ButtonGroup. Renders a <Separator> element and accepts supported separator props; orientation defaults to "vertical", unlike the standalone separator.

className?: string

CSS class applied to the element.

orientation?: Orientation = "vertical"

The orientation of the separator. Defaults to "horizontal".

render?: React.ReactElement<any, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, SeparatorState>

Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a React element or a function that returns the element to render.

style?: React.CSSProperties | ((state: SeparatorState) => React.CSSProperties | undefined)

Style applied to the element, or a function that returns a style object based on the component’s state.