Button Group
@cloudflare/kumo
import { Button, ButtonGroup } from "@cloudflare/kumo";

/**
 * A basic segmented row of related actions joined into a single control.
 */
export function ButtonGroupBasicDemo() {
  return (
    <ButtonGroup>
      <Button variant="secondary">Day</Button>
      <Button variant="secondary">Week</Button>
      <Button variant="secondary">Month</Button>
    </ButtonGroup>
  );
}

Installation

Barrel

import { ButtonGroup } from "@cloudflare/kumo";

Granular

import { ButtonGroup } from "@cloudflare/kumo/components/button-group";

Usage

ButtonGroup is a layout wrapper. Its children keep their own variant, size, and shape — the group only flattens the inner corners and overlaps borders so adjacent buttons share a single seam. Use the same size and variant on every child for a consistent segmented control.

import { Button, ButtonGroup } from "@cloudflare/kumo";

export default function Example() {
return (
  <ButtonGroup>
    <Button variant="secondary">Day</Button>
    <Button variant="secondary">Week</Button>
    <Button variant="secondary">Month</Button>
  </ButtonGroup>
);
}

Examples

Basic

A segmented row of related actions joined into a single control.

import { Button, ButtonGroup } from "@cloudflare/kumo";

/**
 * A basic segmented row of related actions joined into a single control.
 */
export function ButtonGroupBasicDemo() {
  return (
    <ButtonGroup>
      <Button variant="secondary">Day</Button>
      <Button variant="secondary">Week</Button>
      <Button variant="secondary">Month</Button>
    </ButtonGroup>
  );
}

Split button

Pair a primary action with a DropdownMenu trigger for secondary actions. The caret button uses shape="square" and an aria-label.

import { Button, ButtonGroup, DropdownMenu } from "@cloudflare/kumo";
import { CaretDownIcon } from "@phosphor-icons/react";

/**
 * Split button: a primary action joined with a dropdown trigger for secondary
 * actions. The caret button uses `shape="square"` and an `aria-label`.
 */
export function ButtonGroupSplitDemo() {
  return (
    <ButtonGroup>
      <Button variant="primary">Deploy</Button>
      <DropdownMenu>
        <DropdownMenu.Trigger
          render={
            <Button
              variant="primary"
              shape="square"
              aria-label="More deploy options"
            >
              <CaretDownIcon />
            </Button>
          }
        />
        <DropdownMenu.Content>
          <DropdownMenu.Item>Deploy to staging</DropdownMenu.Item>
          <DropdownMenu.Item>Deploy and tail logs</DropdownMenu.Item>
          <DropdownMenu.Item>Schedule deploy…</DropdownMenu.Item>
        </DropdownMenu.Content>
      </DropdownMenu>
    </ButtonGroup>
  );
}

Icon toolbar

Icon-only groups make compact toolbars. Set role="toolbar" and an aria-label describing the set of actions.

import { Button, ButtonGroup } from "@cloudflare/kumo";
import { TextAlignCenterIcon, TextAlignLeftIcon, TextAlignRightIcon } from "@phosphor-icons/react";

/**
 * Icon-only groups work well as toolbars. Set `role="toolbar"` and an
 * `aria-label` to describe the set of actions.
 */
export function ButtonGroupIconDemo() {
  return (
    <ButtonGroup role="toolbar" aria-label="Text alignment">
      <Button variant="secondary" shape="square" aria-label="Align left">
        <TextAlignLeftIcon />
      </Button>
      <Button variant="secondary" shape="square" aria-label="Align center">
        <TextAlignCenterIcon />
      </Button>
      <Button variant="secondary" shape="square" aria-label="Align right">
        <TextAlignRightIcon />
      </Button>
    </ButtonGroup>
  );
}

With icons and labels

Buttons with leading icons, grouped together.

import { Button, ButtonGroup } from "@cloudflare/kumo";
import { CopyIcon, PencilSimpleIcon, TrashIcon } from "@phosphor-icons/react";

/**
 * Buttons with leading icons and labels, grouped together.
 */
export function ButtonGroupWithIconsDemo() {
  return (
    <ButtonGroup>
      <Button variant="secondary" icon={PencilSimpleIcon}>
        Edit
      </Button>
      <Button variant="secondary" icon={CopyIcon}>
        Duplicate
      </Button>
      <Button variant="secondary-destructive" icon={TrashIcon}>
        Delete
      </Button>
    </ButtonGroup>
  );
}

Sizes

Set the same size on every button to keep the group aligned.

import { Button, ButtonGroup } from "@cloudflare/kumo";

/**
 * ButtonGroup respects each child's `size` — set the same size on every button
 * to keep the group aligned.
 */
export function ButtonGroupSizesDemo() {
  return (
    <div className="flex flex-col items-start gap-3">
      <ButtonGroup>
        <Button size="sm" variant="secondary">
          Day
        </Button>
        <Button size="sm" variant="secondary">
          Week
        </Button>
        <Button size="sm" variant="secondary">
          Month
        </Button>
      </ButtonGroup>
      <ButtonGroup>
        <Button size="lg" variant="secondary">
          Day
        </Button>
        <Button size="lg" variant="secondary">
          Week
        </Button>
        <Button size="lg" variant="secondary">
          Month
        </Button>
      </ButtonGroup>
    </div>
  );
}

API Reference

PropTypeDefaultDescription
childrenReactNode-Buttons to join together. Typically `Button` / `LinkButton` elements.
classNamestring-Additional CSS classes merged via `cn()`. Use kumo semantic tokens only.
idstring--
langstring--
titlestring--