Button Group

A segmented action group with shared borders, split primary actions, and dropdown menu support for dense toolbars.

Loading preview

Examples

Practical examples and common states for the same installable component.

Default

Related actions share one boundary, separators, and a single overflow menu.

examples/button-group-default.tsx
"use client";
import {
IconChevronLeft,
IconCopy,
IconDots,
IconFileExport,
IconHistory,
IconShare3,
IconTrash,
} from "@tabler/icons-react";
import {
ButtonGroup,
ButtonGroupItem,
ButtonGroupMenu,
ButtonGroupMenuContent,
ButtonGroupMenuItem,
ButtonGroupMenuLabel,
ButtonGroupMenuSeparator,
ButtonGroupMenuTrigger,
ButtonGroupSeparator,
} from "@/components/wensity/button-group";
export function DraftActions() {
return (
<ButtonGroup aria-label="Draft actions">
<ButtonGroupItem size="icon" aria-label="Previous draft">
<IconChevronLeft />
</ButtonGroupItem>
<ButtonGroupSeparator />
<ButtonGroupItem>Save draft</ButtonGroupItem>
<ButtonGroupSeparator />
<ButtonGroupItem>Publish</ButtonGroupItem>
<ButtonGroupSeparator />
<ButtonGroupItem>Share</ButtonGroupItem>
<ButtonGroupSeparator />
<ButtonGroupMenu>
<ButtonGroupMenuTrigger size="icon" aria-label="More draft actions">
<IconDots />
</ButtonGroupMenuTrigger>
<ButtonGroupMenuContent align="end">
<ButtonGroupMenuLabel>Draft</ButtonGroupMenuLabel>
<ButtonGroupMenuItem icon={<IconCopy />} shortcut="Cmd+D">
Duplicate
</ButtonGroupMenuItem>
<ButtonGroupMenuItem icon={<IconHistory />}>
Version history
</ButtonGroupMenuItem>
<ButtonGroupMenuItem icon={<IconFileExport />}>
Export as PDF
</ButtonGroupMenuItem>
<ButtonGroupMenuSeparator />
<ButtonGroupMenuItem icon={<IconShare3 />}>
Copy invite link
</ButtonGroupMenuItem>
<ButtonGroupMenuSeparator />
<ButtonGroupMenuItem destructive icon={<IconTrash />}>
Delete draft
</ButtonGroupMenuItem>
</ButtonGroupMenuContent>
</ButtonGroupMenu>
</ButtonGroup>
);
}

Split Action

Primary action plus menu trigger, clipped to one rounded control.

examples/button-group-split.tsx
import { IconChevronDown, IconMessageCircle } from "@tabler/icons-react";
import {
ButtonGroup,
ButtonGroupItem,
ButtonGroupMenu,
ButtonGroupMenuContent,
ButtonGroupMenuItem,
ButtonGroupMenuTrigger,
ButtonGroupSeparator,
} from "@/components/wensity/button-group";
export function ConversationActions() {
return (
<ButtonGroup aria-label="Conversation actions">
<ButtonGroupItem leftIcon={<IconMessageCircle />}>
Message
</ButtonGroupItem>
<ButtonGroupSeparator />
<ButtonGroupMenu>
<ButtonGroupMenuTrigger size="icon" aria-label="Conversation options">
<IconChevronDown />
</ButtonGroupMenuTrigger>
<ButtonGroupMenuContent align="end">
<ButtonGroupMenuItem>Rename thread</ButtonGroupMenuItem>
<ButtonGroupMenuItem>Copy thread link</ButtonGroupMenuItem>
</ButtonGroupMenuContent>
</ButtonGroupMenu>
</ButtonGroup>
);
}

Icon Group

Icon-only actions keep fixed dimensions and accessible labels.

examples/button-group-icons.tsx
import {
IconChevronLeft,
IconChevronRight,
IconLayoutSidebarLeftCollapse,
IconLayoutSidebarRightCollapse,
} from "@tabler/icons-react";
import {
ButtonGroup,
ButtonGroupItem,
ButtonGroupSeparator,
} from "@/components/wensity/button-group";
export function PanelActions() {
return (
<ButtonGroup aria-label="Panel layout">
<ButtonGroupItem size="icon" aria-label="Collapse left panel">
<IconLayoutSidebarLeftCollapse />
</ButtonGroupItem>
<ButtonGroupSeparator />
<ButtonGroupItem size="icon" aria-label="Previous item">
<IconChevronLeft />
</ButtonGroupItem>
<ButtonGroupSeparator />
<ButtonGroupItem size="icon" aria-label="Next item">
<IconChevronRight />
</ButtonGroupItem>
<ButtonGroupSeparator />
<ButtonGroupItem size="icon" aria-label="Collapse right panel">
<IconLayoutSidebarRightCollapse />
</ButtonGroupItem>
</ButtonGroup>
);
}

Variants

Group items keep Button variants while the shell owns the shared boundary.

examples/button-group-variants.tsx
import {
ButtonGroup,
ButtonGroupItem,
ButtonGroupSeparator,
} from "@/components/wensity/button-group";
export function ButtonGroupVariants() {
return (
<ButtonGroup aria-label="View density">
<ButtonGroupItem>Default</ButtonGroupItem>
<ButtonGroupSeparator />
<ButtonGroupItem variant="secondary">Secondary</ButtonGroupItem>
<ButtonGroupSeparator />
<ButtonGroupItem variant="ghost">Ghost</ButtonGroupItem>
</ButtonGroup>
);
}

Vertical

Stacked groups use horizontal separators and the same item API.

examples/button-group-vertical.tsx
import {
ButtonGroup,
ButtonGroupItem,
ButtonGroupSeparator,
} from "@/components/wensity/button-group";
export function VerticalActions() {
return (
<ButtonGroup orientation="vertical" aria-label="Stacked actions">
<ButtonGroupItem>Rename</ButtonGroupItem>
<ButtonGroupSeparator orientation="horizontal" />
<ButtonGroupItem>Duplicate</ButtonGroupItem>
<ButtonGroupSeparator orientation="horizontal" />
<ButtonGroupItem variant="destructive">Delete</ButtonGroupItem>
</ButtonGroup>
);
}

Props

PropTypeDefaultDescription
orientation"horizontal" | "vertical""horizontal"Direction the buttons are joined in. Vertical stacks them and moves the shared borders.