# Button Group

Joins related buttons into a single control.

Source: [button-group.tsx](https://github.com/jakejarvis/jarvis-ui/blob/main/src/components/ui/button-group.tsx)

```tsx
import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react";

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

export default function ButtonGroupBasic() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      <ButtonGroup aria-label="Message actions">
        <Button variant="secondary">Archive</Button>
        <Button variant="secondary">Report</Button>
        <Button variant="secondary">Snooze</Button>
      </ButtonGroup>
      <ButtonGroup aria-label="Pagination">
        <Button variant="outline" size="icon" aria-label="Previous">
          <ArrowLeftIcon />
        </Button>
        <Button variant="outline" size="icon" aria-label="Next">
          <ArrowRightIcon />
        </Button>
      </ButtonGroup>
    </div>
  );
}
```

## Installation

Add the registry, once per project:

```bash
npx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json
```

Then add the component:

```bash
npx shadcn@latest add @jarvis/button-group
```

## Usage

```tsx
import { Button } from "@/components/ui/button";
import { ButtonGroup } from "@/components/ui/button-group";

export function MessageActions() {
  return (
    <ButtonGroup aria-label="Message actions">
      <Button variant="secondary">Archive</Button>
      <Button variant="secondary">Report</Button>
      <Button variant="secondary">Snooze</Button>
    </ButtonGroup>
  );
}
```

The group has the `group` role. Give it an `aria-label` when its purpose isn't clear from the
buttons alone.

## Composition

- `ButtonGroup`
  - [`Button`](https://ui.jarv.is/components/button.md)
  - `ButtonGroupSeparator`
  - `ButtonGroupText`

## Examples

### With text

`ButtonGroupText` adds a label or count beside the buttons. For text attached to an input, use
[Input Group](https://ui.jarv.is/components/input-group.md).

```tsx
import { CalendarDaysIcon, StarIcon } from "lucide-react";

import { Button } from "@/components/ui/button";
import { ButtonGroup, ButtonGroupText } from "@/components/ui/button-group";

export default function ButtonGroupWithText() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      <ButtonGroup>
        <ButtonGroupText>
          <CalendarDaysIcon />
          Range
        </ButtonGroupText>
        <Button variant="secondary">Last 30 days</Button>
      </ButtonGroup>
      <ButtonGroup>
        <Button variant="secondary">
          <StarIcon />
          Star
        </Button>
        <ButtonGroupText>1.2k</ButtonGroupText>
      </ButtonGroup>
    </div>
  );
}
```

### Split button

`ButtonGroupSeparator` divides a main action from a menu of related ones.

```tsx
import { ArchiveIcon, ChevronDownIcon, EllipsisIcon } from "lucide-react";

import { Button } from "@/components/ui/button";
import { ButtonGroup, ButtonGroupSeparator } from "@/components/ui/button-group";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

export default function ButtonGroupSplitButton() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      <ButtonGroup>
        <Button variant="primary">Publish</Button>
        <ButtonGroupSeparator />
        <DropdownMenu>
          <DropdownMenuTrigger
            render={<Button variant="primary" size="icon" aria-label="More publish options" />}
          >
            <ChevronDownIcon />
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end">
            <DropdownMenuItem>Schedule for later</DropdownMenuItem>
            <DropdownMenuItem>Save as draft</DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
      </ButtonGroup>
      <ButtonGroup>
        <Button variant="secondary">
          <ArchiveIcon />
          Archive
        </Button>
        <ButtonGroupSeparator />
        <Button variant="secondary" size="icon" aria-label="More options">
          <EllipsisIcon />
        </Button>
      </ButtonGroup>
    </div>
  );
}
```

### Nested

Nest groups to space out sets of buttons.

```tsx
import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react";

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

export default function ButtonGroupNested() {
  return (
    <ButtonGroup aria-label="Pagination">
      <ButtonGroup>
        <Button variant="secondary" size="sm">
          1
        </Button>
        <Button variant="secondary" size="sm">
          2
        </Button>
        <Button variant="secondary" size="sm">
          3
        </Button>
      </ButtonGroup>
      <ButtonGroup>
        <Button variant="secondary" size="icon-sm" aria-label="Previous page">
          <ArrowLeftIcon />
        </Button>
        <Button variant="secondary" size="icon-sm" aria-label="Next page">
          <ArrowRightIcon />
        </Button>
      </ButtonGroup>
    </ButtonGroup>
  );
}
```

### Vertical

Set `orientation="vertical"` to stack the buttons.

```tsx
import { MinusIcon, PlusIcon } from "lucide-react";

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

export default function ButtonGroupVertical() {
  return (
    <ButtonGroup orientation="vertical" aria-label="Zoom">
      <Button variant="secondary" size="icon" aria-label="Zoom in">
        <PlusIcon />
      </Button>
      <Button variant="secondary" size="icon" aria-label="Zoom out">
        <MinusIcon />
      </Button>
    </ButtonGroup>
  );
}
```

## Props

`ButtonGroupText` can render a `<label>` instead of a `<div>` with `render`.

| Part | Extends |
| --- | --- |
| `ButtonGroup` | `<div>` |
| `ButtonGroupText` | `<div>` |
| `ButtonGroupSeparator` | [`Separator`](https://ui.jarv.is/components/separator.md) |

The tables leave out `className`, `style` and `render`. Parts built on Base UI take them as its [styling](https://base-ui.com/react/handbook/styling) and [composition](https://base-ui.com/react/handbook/composition) guides describe.

### ButtonGroup

| Prop           | Type                         | Description             |
| -------------- | ---------------------------- | ----------------------- |
| `orientation?` | `"horizontal" \| "vertical"` | Default: `"horizontal"` |

### ButtonGroupSeparator

| Prop           | Type                         | Description                                             |
| -------------- | ---------------------------- | ------------------------------------------------------- |
| `orientation?` | `"horizontal" \| "vertical"` | The orientation of the separator. Default: `"vertical"` |
