# Button Group

Joins buttons, inputs and text into one control, across or down.

> Every page: https://constella.aayush.cv/llms.txt

```tsx
<ButtonGroup aria-label="Message actions">
  <ButtonGroup>
    <Button aria-label="Go back" size="icon" variant="outline">
      <ArrowLeftIcon data-rtl-flip />
    </Button>
  </ButtonGroup>
  <ButtonGroup>
    <Button variant="outline">Archive</Button>
    <Button variant="outline">Report</Button>
  </ButtonGroup>
  <ButtonGroup>
    <Button variant="outline">Snooze</Button>
    <DropdownMenu>
      <DropdownMenuTrigger
        render={
          <Button aria-label="More options" size="icon" variant="outline" />
        }
      >
        <MoreHorizontalIcon />
      </DropdownMenuTrigger>
      <DropdownMenuContent align="end">
        <DropdownMenuItem>Mark as Read</DropdownMenuItem>
        <DropdownMenuItem>Archive</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  </ButtonGroup>
</ButtonGroup>
```

## Installation

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

## Usage

```tsx
import {
  ButtonGroup,
  ButtonGroupSeparator,
  ButtonGroupText,
} from "@/components/primitives/button-group";
```

```tsx
<ButtonGroup>
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</ButtonGroup>
```

## Composition

```
ButtonGroup
├── Button
├── ButtonGroupSeparator
├── ButtonGroupText
└── ButtonGroup
```

## Accessibility

`ButtonGroup` has `role="group"`. Label it with `aria-label` or `aria-labelledby`; <kbd>Tab</kbd> moves between its buttons.

Use `ButtonGroup` for buttons that act. For buttons that toggle a state, use a toggle group.

## Orientation

Use `orientation="vertical"` to stack the group.

```tsx
<ButtonGroup aria-label="Media controls" orientation="vertical">
  <Button aria-label="Volume up" size="icon" variant="outline">
    <PlusIcon />
  </Button>
  <Button aria-label="Volume down" size="icon" variant="outline">
    <MinusIcon />
  </Button>
</ButtonGroup>
```

## Size

Set `size` on each button; the group takes their height.

```tsx
<ButtonGroup>
  <Button size="sm" variant="outline">
    Small
  </Button>
  <Button size="sm" variant="outline">
    Button
  </Button>
  <Button aria-label="Add" size="icon-sm" variant="outline">
    <PlusIcon />
  </Button>
</ButtonGroup>
```

## Nested

Nest groups to space them apart.

```tsx
<ButtonGroup aria-label="Pagination">
  <ButtonGroup>
    <Button size="sm" variant="outline">
      1
    </Button>
    <Button size="sm" variant="outline">
      2
    </Button>
  </ButtonGroup>
  <ButtonGroup>
    <Button aria-label="Previous" size="icon-sm" variant="outline">
      <ArrowLeftIcon data-rtl-flip />
    </Button>
    <Button aria-label="Next" size="icon-sm" variant="outline">
      <ArrowRightIcon data-rtl-flip />
    </Button>
  </ButtonGroup>
</ButtonGroup>
```

## Separator

Add `ButtonGroupSeparator` between buttons without an edge. `outline` buttons have one, so they don't need it.

```tsx
<ButtonGroup>
  <Button size="sm">Copy</Button>
  <ButtonGroupSeparator />
  <Button size="sm">Paste</Button>
</ButtonGroup>
```

## Split

Pair an action with an icon button, split by a separator.

```tsx
<ButtonGroup>
  <Button>Button</Button>
  <ButtonGroupSeparator />
  <Button aria-label="Add" size="icon">
    <PlusIcon />
  </Button>
</ButtonGroup>
```

## Text

Use `ButtonGroupText` for a fixed prefix or suffix. Pass `render` to make it a label.

```tsx
<ButtonGroup>
  <ButtonGroupText render={<label htmlFor="url" />}>https://</ButtonGroupText>
  <InputGroup>
    <InputGroupInput id="url" />
    <InputGroupAddon align="inline-end">
      <LinkIcon />
    </InputGroupAddon>
  </InputGroup>
  <ButtonGroupText>.com</ButtonGroupText>
</ButtonGroup>
```

## Input

Put an `Input` in the group to join it to a button.

```tsx
<ButtonGroup>
  <Input aria-label="Search" placeholder="Search..." />
  <Button aria-label="Search" size="icon" variant="outline">
    <SearchIcon />
  </Button>
</ButtonGroup>
```

## Input Group

Put an `InputGroup` in the group for an input with its own addons.

```tsx
<ButtonGroup>
  <ButtonGroup>
    <Button aria-label="Add" size="icon" variant="outline">
      <PlusIcon />
    </Button>
  </ButtonGroup>
  <ButtonGroup>
    <InputGroup>
      <InputGroupInput aria-label="Message" placeholder="Send a message..." />
      <InputGroupAddon align="inline-end">
        <Tooltip>
          <TooltipTrigger
            render={
              <InputGroupButton
                aria-label="Voice mode"
                aria-pressed={voice}
                onClick={() => setVoice(!voice)}
                size="icon-xs"
              />
            }
          >
            <AudioLinesIcon />
          </TooltipTrigger>
          <TooltipContent>Voice mode</TooltipContent>
        </Tooltip>
      </InputGroupAddon>
    </InputGroup>
  </ButtonGroup>
</ButtonGroup>
```

## Dropdown Menu

Render the last button as a [Dropdown Menu](https://constella.aayush.cv/docs/components/dropdown-menu/index.md) trigger for a split button with more actions.

```tsx
<ButtonGroup>
  <Button variant="outline">Follow</Button>
  <DropdownMenu>
    <DropdownMenuTrigger
      render={
        <Button aria-label="More actions" size="icon" variant="outline" />
      }
    >
      <ArrowDown01Icon />
    </DropdownMenuTrigger>
    <DropdownMenuContent align="end">
      <DropdownMenuItem>Mute Conversation</DropdownMenuItem>
      <DropdownMenuItem color="danger">Delete Conversation</DropdownMenuItem>
    </DropdownMenuContent>
  </DropdownMenu>
</ButtonGroup>
```

## Select

Put a [Select](https://constella.aayush.cv/docs/components/select/index.md) beside an input, like a currency before an amount.

```tsx
<ButtonGroup>
  <Select items={currencies} onValueChange={setCurrency} value={currency}>
    <SelectTrigger>{currency}</SelectTrigger>
    <SelectContent align="start" alignItemWithTrigger={false}>
      {currencies.map((item) => (
        <SelectItem key={item.value} value={item.value}>
          {item.value} {item.label}
        </SelectItem>
      ))}
    </SelectContent>
  </Select>
  <Input placeholder="10.00" />
</ButtonGroup>
```

## Popover

Render the last button as a [Popover](https://constella.aayush.cv/docs/components/popover/index.md) trigger for options that need more room.

```tsx
<ButtonGroup>
  <Button variant="outline">Copilot</Button>
  <Popover>
    <PopoverTrigger
      render={
        <Button aria-label="Open Popover" size="icon" variant="outline" />
      }
    >
      <ArrowDown01Icon />
    </PopoverTrigger>
    <PopoverContent align="end">
      <PopoverHeader>
        <PopoverTitle>Start a new task with Copilot</PopoverTitle>
        <PopoverDescription>
          Describe your task in natural language.
        </PopoverDescription>
      </PopoverHeader>
      <Textarea placeholder="I need to..." />
    </PopoverContent>
  </Popover>
</ButtonGroup>
```

## API Reference

### ButtonGroup

A `div` with `role="group"`. Takes every `div` prop, plus `sx`, applied last.

| Prop          | Values                         | Default        |
| ------------- | ------------------------------ | -------------- |
| `orientation` | `"horizontal"` \| `"vertical"` | `"horizontal"` |

### ButtonGroupSeparator

A [Separator](https://constella.aayush.cv/docs/components/separator/index.md) that fits between the group's items.

| Prop          | Values                         | Default      |
| ------------- | ------------------------------ | ------------ |
| `orientation` | `"horizontal"` \| `"vertical"` | `"vertical"` |

### ButtonGroupText

Takes every `div` prop, plus `sx`, applied last.

| Prop     | Values               | Default |
| -------- | -------------------- | ------- |
| `render` | `React.ReactElement` |         |
