Summit
ComponentsActions

Button Group

A Button Group joins related Buttons into one control to show users that their actions belong together.

When to Use

  • for actions on one record that belong together, such as “Duplicate”, “Download”, and “Archive” on an invoice
  • to place a Dropdown Menu of further actions next to a main one, such as “Send invoice”
  • to join a Button or a Select to an Input, for example a currency to an amount

When Not to Use

Anatomy

Page 2 of 8
ElementUsage
ButtonRequired
GroupRequired
TextOptional
SeparatorOptional

ButtonGroupText displays text that isn’t a Button.

Use a separator between secondary Buttons, as they have no visible border and users can’t see where one Button ends.

DoPlace a separator between Buttons that have no visible border.
Don’tWhen the separator is left out, users read the two Buttons as one.

Behavior

A Button Group changes the corners and the spacing of its children; each Button keeps its own variant, size, and action. The group itself has no state.

Orientation

To stack the children and join them from top to bottom, set orientation="vertical"; each child is then as wide as the widest one. If the group is vertical, set orientation="horizontal" on its separators.

Nested Groups

If a Button Group contains other Button Groups, it places them 8px apart and doesn’t join them.

Beside a Field

A Button Group can contain an Input, an Input Group, or a Select. An Input fills the width that remains next to the Buttons, and a Select stays as wide as its value.

Accessibility

A Button Group is a div with role="group". It adds no keys: users press Tab to move to each Button in turn, and the arrow keys do nothing.

To name a Button Group for screen readers, set aria-label, as “Invoice actions” does in the preview.

An icon-only Button in a group needs its own aria-label. See Button for the rule.

Installation

npx shadcn@latest add @summit/button-group

The CLI also adds @summit/separator. It doesn’t add Button.

Usage

import { Button } from '@/components/ui/button';
import { ButtonGroup } from '@/components/ui/button-group';

<ButtonGroup aria-label="Invoice actions">
    <Button variant="outline">Duplicate</Button>
    <Button variant="outline">Download</Button>
    <Button variant="outline">Archive</Button>
</ButtonGroup>;

With a Separator

To separate Buttons that have no visible border, place a ButtonGroupSeparator between them.

With a Separator
import { ButtonGroup, ButtonGroupSeparator } from '@/components/ui/button-group';

<ButtonGroup aria-label="Clipboard">
    <Button variant="secondary">Copy</Button>
    <ButtonGroupSeparator />
    <Button variant="secondary">Paste</Button>
</ButtonGroup>;

With a Menu

To add a menu of further actions, pass the second Button to DropdownMenuTrigger through render. The trigger is joined to the group like any other Button.

With a Menu
import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuItem,
    DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { CaretDownIcon } from '@phosphor-icons/react';

<ButtonGroup>
    <Button variant="outline">Send invoice</Button>
    <DropdownMenu>
        <DropdownMenuTrigger render={<Button variant="outline" size="icon" aria-label="More actions" />}>
            <CaretDownIcon />
        </DropdownMenuTrigger>
        <DropdownMenuContent align="end">
            <DropdownMenuItem>Send reminder</DropdownMenuItem>
            <DropdownMenuItem>Mark as paid</DropdownMenuItem>
        </DropdownMenuContent>
    </DropdownMenu>
</ButtonGroup>;

With an Input

With an Input
import { Input } from '@/components/ui/input';
import { MagnifyingGlassIcon } from '@phosphor-icons/react';

<ButtonGroup>
    <Input aria-label="Search invoices" placeholder="Search invoices" />
    <Button variant="outline" size="icon" aria-label="Search">
        <MagnifyingGlassIcon />
    </Button>
</ButtonGroup>;

API Reference

ButtonGroup and ButtonGroupText accept the props of a div, and ButtonGroupSeparator accepts the props of the Separator that it renders. ButtonGroupText also accepts render, which replaces the div with another element. See the Base UI useRender documentation for render.

ButtonGroup

PropTypeDefaultDescription
orientation'horizontal' | 'vertical''horizontal'The axis along which the children are joined

ButtonGroupSeparator

PropTypeDefaultDescription
orientation'horizontal' | 'vertical''vertical'The direction of the line. Set 'horizontal' in a vertical group.

On this page