# SplitButton

**When to use:** A primary action button with a small attached dropdown for closely related secondary actions, e.g. "Save ▾" opening "Save as draft" / "Save and close". Built from `Button`, `ButtonGroup` and [Menu](Menu.md) internally, rather than a mechanism of its own. Reach for `Menu` on its own when there is no primary action to weld the list to.

**Keywords:** dropdown button, button with menu

**Import:** `import { SplitButton } from '@ahrowe/ui'`
**Types:** `import type { SplitButtonAction, SplitButtonProps } from '@ahrowe/ui'`  
**Enums:** `import { PopoverAlign } from '@ahrowe/ui'` for `align`.

```tsx
import { SplitButton, ThemeColor } from '@ahrowe/ui';
import type { SplitButtonAction } from '@ahrowe/ui';

const actions: SplitButtonAction[] = [
  { id: 'draft', label: 'Save as draft', onClick: () => saveDraft() },
  { id: 'close', label: 'Save and close', onClick: () => saveAndClose() },
];

<SplitButton actions={actions} onClick={() => save()}>
  Save
</SplitButton>

// Destructive, with Button's own style and colour
import { ButtonStyleType } from '@ahrowe/ui';

<SplitButton
  actions={[{ id: 'archive', label: 'Archive instead', onClick: () => archive() }]}
  color={ThemeColor.Error}
  onClick={() => deleteItem()}
>
  Delete
</SplitButton>

// A disabled action within the menu
<SplitButton
  actions={[
    { id: 'draft', label: 'Save as draft', onClick: () => saveDraft() },
    { id: 'archive', label: 'Archive instead', onClick: () => archive(), disabled: true },
  ]}
  onClick={() => save()}
>
  Save
</SplitButton>

// Loading / disabled — both the primary and trigger button reflect the state
<SplitButton actions={actions} onClick={() => save()} isLoading>
  Save
</SplitButton>
<SplitButton actions={actions} onClick={() => save()} disabled>
  Save
</SplitButton>
```

**SplitButtonAction:**

| Field | Type | Description |
|-------|------|-------------|
| `id` | `string` | Stable key for the action |
| `label` | `ReactNode` | Text shown in the dropdown |
| `onClick` | `() => void` | Called when the action is picked; the dropdown closes automatically afterward |
| `disabled` | `boolean` | Dims the action and prevents it from firing |

**Key props:**

| Prop | Type | Description |
|------|------|-------------|
| `children` | `ReactNode` | The primary button's label |
| `onClick` | `(event) => void \| Promise<void>` | The primary button's click handler |
| `actions` | `SplitButtonAction[]` | Secondary actions shown in the dropdown |
| `styleType` | `ButtonStyleType` | Shared by both the primary and trigger button (default `Filled`) |
| `color` | `ColorValue` | Shared by both buttons (default `Primary`); or any CSS colour, as on Button |
| `size` | `ButtonSize` | Size variant, shared by both buttons (default `Medium`) |
| `disabled` | `boolean` | Disables both the primary and trigger button |
| `isLoading` | `boolean` | Shows a spinner on the primary button (same as `Button`'s own `isLoading`) |
| `align` | `PopoverAlign` | Which edge of the group the menu lines up with (default `End`, the chevron's side). The menu is a [Menu](Menu.md), hence `Popover`'s enum |

**`isLoading` vs. `disabled`:** `isLoading` only affects the primary button — the trigger and its menu stay usable while the primary action is in flight, e.g. to cancel via a menu action. To lock the whole control during the async action instead, pass both: `isLoading={isSaving} disabled={isSaving}`. Setting `disabled` also closes the menu if it happened to be open already, and blocks any in-flight click on a menu action.

**Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ SplitButton: { styleType: ButtonStyleType.Outlined } }}`. See [ConfigProvider.md](ConfigProvider.md).

**Keyboard:** the list is a [Menu](Menu.md), so it behaves like one: `↓` `↑` move between actions and skip disabled ones, `Home` and `End` jump to either end, typing a letter jumps to the action that starts with it, `Enter` and `Space` run the focused action, and `Escape` closes and hands the focus back. A click opens the menu without taking the focus, so nothing is marked until you point at an action or press an arrow key; opening with the keyboard focuses the first action straight away. The trigger announces itself as a menu button.

**Slots:** `root` `primaryButton` `triggerButton` `menu` `menuItem` (`menu` is Menu's list, `menuItem` one of its rows)

**Labels:** `moreActions` — the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `SplitButtonLabels`.
