# Button Group

Groups related action buttons, text pills, inputs, and nested control clusters into a single visual control boundary.

Use Button Group for toolbars, split actions, search bars, and compact action clusters where neighboring controls should read as one control family rather than isolated buttons.

## Import

```ts
import { ButtonComponent } from '@edsis/component/button';
import {
  ButtonGroupComponent,
  ButtonGroupSeparatorComponent,
  ButtonGroupTextComponent,
} from '@edsis/component/button-group';
import { InputComponent } from '@edsis/component/input';
import {
  InputGroupAddonComponent,
  InputGroupComponent,
  InputGroupInputComponent,
  InputGroupTextComponent,
} from '@edsis/component/input-group';
```

## Composition

The Angular structure mirrors the shadcn composition while translating `asChild` to normal Angular content projection.

```text
ButtonGroup
├── button[Button] or a[Button]
├── input[Input] or textarea[Textarea]
├── ButtonGroupText
├── ButtonGroupSeparator
└── ButtonGroup
```

## Basic usage

Label the group with `aria-label` or `aria-labelledby` whenever the buttons act as a single tool cluster.

```html
<ButtonGroup aria-label="Search actions" class="w-full max-w-md">
  <input Input placeholder="Search..." />
  <button Button type="button" variant="outline" aria-label="Run search">Search</button>
</ButtonGroup>
```

## Common patterns

### Orientation

Use `orientation="vertical"` when the group should stack actions instead of lining them up horizontally.

```html
<ButtonGroup orientation="vertical" aria-label="Zoom controls" class="h-fit">
  <button Button type="button" variant="outline" size="icon">+</button>
  <button Button type="button" variant="outline" size="icon">-</button>
</ButtonGroup>
```

### Text and field pairing

`ButtonGroupText` is the Angular translation of shadcn's `ButtonGroupText`. Project any semantic content inside it, including a native label.

```html
<ButtonGroup class="w-full max-w-lg">
  <ButtonGroupText>
    <label for="project-name">Project</label>
  </ButtonGroupText>
  <input Input id="project-name" placeholder="Type a name..." />
</ButtonGroup>
```

### Separator

Use `ButtonGroupSeparator` when filled or secondary buttons still need a visible division.

```html
<ButtonGroup aria-label="Clipboard actions">
  <button Button type="button" variant="secondary" size="sm">Copy</button>
  <ButtonGroupSeparator />
  <button Button type="button" variant="secondary" size="sm">Paste</button>
</ButtonGroup>
```

### Split action

Split buttons are just two neighboring buttons with a separator between the primary action and the disclosure or icon action.

```html
<ButtonGroup aria-label="Create actions">
  <button Button type="button" variant="secondary">Create</button>
  <ButtonGroupSeparator />
  <button Button type="button" variant="secondary" size="icon" aria-label="Open create menu">
    +
  </button>
</ButtonGroup>
```

### Search input

Button Group works directly with the local `Input` primitive because both controls own their border on the host element.

```html
<ButtonGroup aria-label="Repository search" class="w-full max-w-lg">
  <input Input placeholder="Search repositories..." />
  <button Button type="button" variant="outline" aria-label="Search">Search</button>
</ButtonGroup>
```

### Nested groups

Nest `ButtonGroup` when you want separate clusters with spacing between them while keeping each inner cluster visually fused.

```html
<ButtonGroup aria-label="Message composer" class="w-full max-w-xl">
  <ButtonGroup>
    <button Button type="button" variant="outline" size="icon" aria-label="Add attachment">
      +
    </button>
  </ButtonGroup>

  <ButtonGroup class="min-w-0 flex-1">
    <InputGroup>
      <input InputGroupInput placeholder="Send a message..." />
      <InputGroupAddon align="inline-end">
        <InputGroupText>⌘↵</InputGroupText>
      </InputGroupAddon>
    </InputGroup>
  </ButtonGroup>
</ButtonGroup>
```

### Popover companion

Use a neighboring popover trigger when the primary button opens a short follow-up form or assistant prompt.

```html
<ButtonGroup aria-label="Copilot actions">
  <button Button type="button" variant="outline">Copilot</button>
  <button Button type="button" variant="outline" size="icon" aria-label="Open Copilot options">
    ⋯
  </button>
</ButtonGroup>
```

## API reference

### `ButtonGroupComponent`

| Input         | Type                         | Default        |
| ------------- | ---------------------------- | -------------- |
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` |
| `class`       | `string`                     | `''`           |

Host behavior:

- Renders `role="group"`.
- Adds `data-orientation` and `data-slot="button-group"`.
- Collapses adjoining corner radius and internal border width with RTL-safe logical properties.

### `ButtonGroupSeparatorComponent`

| Input         | Type                         | Default      |
| ------------- | ---------------------------- | ------------ |
| `orientation` | `'horizontal' \| 'vertical'` | `'vertical'` |
| `class`       | `string`                     | `''`         |

### `ButtonGroupTextComponent`

| Input   | Type     | Default |
| ------- | -------- | ------- |
| `class` | `string` | `''`    |

Angular mapping note: there is no `asChild` input. Project the semantic element you need, such as `<label>` or `<span>`, inside `ButtonGroupText`.

## Styling and theming

- The root collapses adjacent corners and borders with logical start/end utilities so the same component works in LTR and RTL layouts.
- Nested `ButtonGroup` children automatically create spacing between groups while preserving the fused inner boundaries of each nested group.
- `ButtonGroupText` uses `border-border`, `bg-muted`, and shared radius tokens so it matches the rest of the component package.
- `Input` and `InputGroup` compose cleanly inside Button Group because their border and radius live on the visible host. The current `SelectField` does not expose the same host-level border contract yet, so the upstream Select example is intentionally not shipped as a parity demo.

## Accessibility

- `ButtonGroup` renders with `role="group"`; provide an accessible name with `aria-label` or `aria-labelledby` when the controls act as one tool cluster.
- Button Group is for actions. If the clustered controls represent pressed or selected state, use a toggle-group style pattern instead.
- Add `aria-label` to icon-only buttons inside the group.
- `ButtonGroupText` is non-interactive content. Keep labels, helper text, or status copy inside it and leave action handling to the actual button or input controls.

## Keyboard interactions

- Tab order follows the DOM order of the projected controls.
- Native buttons keep their built-in Enter and Space activation behavior.
- Inputs and textareas keep their native editing behavior.
- Popover and menu triggers inside a group keep the keyboard behavior of their own directives; the group container does not intercept those interactions.

## Button Group vs Toggle Group

- Use Button Group when each item performs an immediate action.
- Use Toggle Group when each item represents persistent pressed, selected, or filter state.

## Angular notes

- Import `ButtonGroupComponent` plus only the child primitives you render on the page.
- There is no React-style `asChild` prop. Angular templates already let you choose the semantic element directly.
- Use nested `ButtonGroup` elements for spacing between related clusters rather than adding gap utilities to a single fused group.

## Source parity

This Angular implementation follows the shadcn Button Group surface with a grouped root, text pill, separator, nested-group spacing, dropdown and popover composition, and RTL-friendly border collapsing.

The main documented deviation is the upstream Select example: the local `SelectField` places its border on an inner trigger button, so it is better composed next to the group in surrounding layout for now instead of being presented as a fused host-level group item.
