Propel

Button Group

A connected group of related buttons that share one size.

Show code
import { ButtonGroup, ButtonGroupButton } from "@makeplane/propel/components/button-group";
import { Icon } from "@makeplane/propel/components/icon";
import { Clipboard, Copy, Scissors } from "lucide-react";

export default function BasicDemo() {
  return (
    <ButtonGroup size="sm" aria-label="Clipboard actions">
      <ButtonGroupButton label="Cut" icon={<Icon icon={Scissors} />} />
      <ButtonGroupButton label="Copy" icon={<Icon icon={Copy} />} />
      <ButtonGroupButton label="Paste" icon={<Icon icon={Clipboard} />} />
    </ButtonGroup>
  );
}

Installation

import { ButtonGroup, ButtonGroupButton } from "@makeplane/propel/components/button-group";

Usage

ButtonGroup is a group-role container that shares its size with every ButtonGroupButton inside via context. Name the group for assistive tech with aria-label.

import { ButtonGroup, ButtonGroupButton } from "@makeplane/propel/components/button-group";
import { Icon } from "@makeplane/propel/components/icon";
import { Clipboard, Copy, Scissors } from "lucide-react";

export default function BasicDemo() {
  return (
    <ButtonGroup size="sm" aria-label="Clipboard actions">
      <ButtonGroupButton label="Cut" icon={<Icon icon={Scissors} />} />
      <ButtonGroupButton label="Copy" icon={<Icon icon={Copy} />} />
      <ButtonGroupButton label="Paste" icon={<Icon icon={Clipboard} />} />
    </ButtonGroup>
  );
}

Examples

Sizes

The group’s size sizes every segment — a segment’s own size still wins. There is no lg grouped button.

Show code
import { ButtonGroup, ButtonGroupButton } from "@makeplane/propel/components/button-group";
import { Icon } from "@makeplane/propel/components/icon";
import { Clipboard, Copy, Scissors } from "lucide-react";

export default function SizesDemo() {
  return (
    <div className="flex flex-col items-start gap-6">
      {(["sm", "md"] as const).map((size) => (
        <ButtonGroup key={size} size={size} aria-label={`Clipboard actions (${size})`}>
          <ButtonGroupButton label="Cut" icon={<Icon icon={Scissors} />} />
          <ButtonGroupButton label="Copy" icon={<Icon icon={Copy} />} />
          <ButtonGroupButton label="Paste" icon={<Icon icon={Clipboard} />} />
        </ButtonGroup>
      ))}
    </div>
  );
}

Disabled

A disabled segment is hard-disabled (not focusable) while its siblings stay interactive.

Show code
import { ButtonGroup, ButtonGroupButton } from "@makeplane/propel/components/button-group";
import { Icon } from "@makeplane/propel/components/icon";
import { Clipboard, Copy, Scissors } from "lucide-react";

export default function DisabledDemo() {
  return (
    <ButtonGroup size="sm" aria-label="Clipboard actions">
      <ButtonGroupButton label="Cut" icon={<Icon icon={Scissors} />} />
      <ButtonGroupButton label="Copy" icon={<Icon icon={Copy} />} />
      <ButtonGroupButton label="Paste" icon={<Icon icon={Clipboard} />} disabled />
    </ButtonGroup>
  );
}

API Reference

ButtonGroup

The ready-made connected button group: a `group`-role container that shares `size` with every `ButtonGroupButton` inside via context (an item's own `size` still wins). There is no Base UI button-group primitive — the items are independent Base UI `Button`s; the group contributes only the shared chrome and the `group` role. Name the group for assistive tech via `aria-label`.

PropTypeDefaultDescription
size(required)"sm" | "md"Size applied to every `ButtonGroupButton` in the group (each can still override it).
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. Accepts a `ReactElement` or a function that returns the element to render.

ButtonGroupButton

The ready-made group segment: grafts Base UI's `Button` behavior onto the styled `ButtonGroupButton` (behavior outer, the styled button as the render target), lays out an optional `icon` beside the label (`iconPosition`), and takes its `size` from the surrounding `ButtonGroup` via context.

PropTypeDefaultDescription
label(required)stringVisible button label.
type"button" | "submit" | "reset"buttonThe button's form behavior.
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. Accepts a `ReactElement` or a function that returns the element to render.
nativeButtonbooleanSet `false` when `render` swaps the underlying tag away from `<button>` (e.g. an `<a>`): Base UI then adds `role="button"`, tab focus, and Enter/Space activation.
size"sm" | "md""sm"Size override. Inside a `ButtonGroup` the group's `size` is used (so you can omit it); standalone it defaults to `sm`.
iconReactNodeIcon rendered beside the label (inline-start by default), e.g. `<Icon icon={Plus} />`.
iconPosition"start" | "end"startWhich side of the label the icon sits on.