Skip to content
UI

Button Group

Joins related buttons, inputs and labels into one control with shared borders.

@zenoxai/ui/components/button-group Markdown
<ButtonGroup aria-label="Alert actions">
  <Button variant="outline">Acknowledge</Button>
  <Button variant="outline">Assign</Button>
  <Button variant="outline">Resolve</Button>
</ButtonGroup>

Usage

import { Button } from "@zenoxai/ui/components/button"
import { ButtonGroup } from "@zenoxai/ui/components/button-group"

export function AlertActions() {
  return (
    <ButtonGroup aria-label="Alert actions">
      <Button variant="outline">Acknowledge</Button>
      <Button variant="outline">Assign</Button>
      <Button variant="outline">Resolve</Button>
    </ButtonGroup>
  )
}

Use a button group for actions that act on the same object and belong together, such as the actions on an alert, or to attach a button to an input. The group only changes layout: it squares the inner corners and merges the borders of its direct children.

Use something else when:

  • The buttons hold a selection state (a layout switch, a time range): use a Toggle Group.
  • There are more than three or four actions: keep the main one visible and move the rest into a Dropdown Menu.

Use the same variant and size for every button in a group. Mixed heights break the shared borders.

Examples

Nested

A ButtonGroup inside another adds an 8px gap between the inner groups. Use it for toolbars made of several clusters, like pagination.

<ButtonGroup aria-label="Pagination">
  <ButtonGroup>
    <Button variant="outline" size="icon" aria-label="Previous page">
      <ChevronLeftIcon />
    </Button>
    <Button variant="outline" size="icon" aria-label="Next page">
      <ChevronRightIcon />
    </Button>
  </ButtonGroup>
  <ButtonGroup>
    <Button variant="outline">1</Button>
    <Button variant="outline">2</Button>
    <Button variant="outline">3</Button>
  </ButtonGroup>
</ButtonGroup>

Split button

A main action with a menu of variations next to it. ButtonGroupSeparator draws the divider between two filled buttons, which have no border of their own.

<ButtonGroup>
  <Button>Export report</Button>
  <ButtonGroupSeparator />
  <DropdownMenu>
    <DropdownMenuTrigger
      render={<Button size="icon" aria-label="More export formats" />}
    >
      <ChevronDownIcon />
    </DropdownMenuTrigger>
    <DropdownMenuContent align="end" className="w-40">
      <DropdownMenuItem>Export as PDF</DropdownMenuItem>
      <DropdownMenuItem>Export as CSV</DropdownMenuItem>
      <DropdownMenuItem>Export as JSON</DropdownMenuItem>
    </DropdownMenuContent>
  </DropdownMenu>
</ButtonGroup>

With an input

An Input inside the group stretches to fill the row. ButtonGroupText renders a static prefix or suffix, such as a protocol or a unit, with the same borders.

https://
<div className="flex w-full max-w-sm flex-col gap-3">
  <ButtonGroup className="w-full">
    <Input aria-label="Search domains" placeholder="Search domains" />
    <Button variant="outline" size="icon" aria-label="Search">
      <SearchIcon />
    </Button>
  </ButtonGroup>
  <ButtonGroup className="w-full">
    <ButtonGroupText>https://</ButtonGroupText>
    <Input aria-label="Domain" placeholder="login.acme-corp.com" />
  </ButtonGroup>
</div>

Vertical

orientation="vertical" stacks the children and merges their top and bottom borders, for compact controls such as map zoom.

<ButtonGroup orientation="vertical" aria-label="Map zoom">
  <Button variant="outline" size="icon" aria-label="Zoom in">
    <PlusIcon />
  </Button>
  <Button variant="outline" size="icon" aria-label="Zoom out">
    <MinusIcon />
  </Button>
</ButtonGroup>

Accessibility

  • ButtonGroup renders role="group". Give it an aria-label when the purpose is not clear from the buttons alone (“Alert actions”, “Pagination”).
  • Every button keeps its own tab stop; the group adds no arrow-key navigation. For a single tab stop with arrow keys, use a Toggle Group.
  • Icon-only buttons need an aria-label. ButtonGroupText is plain text: an input next to it still needs its own label.

API reference

Generated from the TypeScript source. className, style and children are accepted everywhere and omitted below.

ButtonGroup

ButtonGroup joins related buttons, inputs and selects into one bar with shared borders, such as a split button or a field with its submit button. For a set of toggles where one or several are on, use ToggleGroup.

PropTypeDefault
orientation"horizontal" | "vertical" | null

`horizontal` (default) joins the items side by side; `vertical` stacks them.

horizontal

ButtonGroupSeparator

ButtonGroupSeparator draws a divider between two items whose joined edges would not show one, such as two borderless secondary buttons.

PropTypeDefault
orientation"horizontal" | "vertical"

The orientation of the separator.

vertical
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, SeparatorState>

Allows you to replace the component's HTML element with a different tag, or compose it with another component.

-

ButtonGroupText

ButtonGroupText is a static segment of the bar, such as a label or a unit, styled to match the buttons beside it.

PropTypeDefault
renderReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>

Allows you to replace the component's HTML element with a different tag, or compose it with another component.

-