# ActionMenu

> A compact “more actions” menu built from an array, ideal for table rows and cards.

Category: Actions · Status: stable · Package: @bindshq/stance-react@0.1.1 · Docs: https://stanceui.com/components/action-menu

ActionMenu is a convenience over DropdownMenu for the common overflow pattern: an icon button that reveals row-level or card-level actions. Describe the actions as data (labels, icons, shortcuts, separators, groups and submenus) and it renders an accessible menu. Use DropdownMenu directly when you need checkable items or custom content.

## Import

```tsx
import { ActionMenu, type ActionMenuItem } from '@bindshq/stance-react';
```

Styles are imported once per app: `@bindshq/stance-tokens/css` and `@bindshq/stance-react/styles.css`.

## Examples

### Basic

```tsx
import { ActionMenu, Icon } from '@bindshq/stance-react';
import type { ActionMenuItem } from '@bindshq/stance-react';

const signatureActions: ActionMenuItem[] = [
  { label: 'Edit signature', icon: <Icon name="pencil" />, shortcut: '⌘E' },
  { label: 'Duplicate', icon: <Icon name="copy" /> },
  { label: 'Preview in Outlook', icon: <Icon name="eye" /> },
  { type: 'separator' },
  { label: 'Delete', icon: <Icon name="trash" />, destructive: true },
];

export function Basic() {
  return <ActionMenu items={signatureActions} />;
}
```

### Groups and submenus

```tsx
import { ActionMenu, Icon } from '@bindshq/stance-react';

export function GroupsAndSubmenus() {
  return (
    <ActionMenu
      label="Template options"
      orientation="vertical"
      items={[
        {
          type: 'group',
          label: 'Template',
          items: [
            { label: 'Customise', icon: <Icon name="sliders" /> },
            { label: 'Rename', icon: <Icon name="pencil" /> },
          ],
        },
        {
          label: 'Export',
          icon: <Icon name="download" />,
          items: [{ label: 'HTML file' }, { label: 'PNG image' }, { label: 'Copy to clipboard' }],
        },
        { label: 'Assign to department', icon: <Icon name="users" />, disabled: true },
        { type: 'separator' },
        { label: 'Archive template', icon: <Icon name="inbox" />, destructive: true },
      ]}
    />
  );
}
```

### In a table row

Give each trigger a unique label so screen-reader users know which row it acts on.

```tsx
import { ActionMenu, Icon } from '@bindshq/stance-react';

export function InARow() {
  const people = ['Amara Okafor', 'Ben Hughes', 'Chen Wei'];
  return (
    <div style={{ width: '100%', maxWidth: 520 }}>
      {people.map((name) => (
        <div
          key={name}
          style={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'space-between',
            padding: '10px 4px',
            borderBottom: '1px solid var(--st-color-separator)',
            fontSize: 'var(--st-font-size-sm)',
          }}
        >
          <span>{name}</span>
          <ActionMenu
            label={`Actions for ${name}`}
            items={[
              { label: 'Edit signature', icon: <Icon name="pencil" /> },
              { label: 'Resend invite', icon: <Icon name="send" /> },
              { type: 'separator' },
              { label: 'Remove from organisation', icon: <Icon name="trash" />, destructive: true },
            ]}
          />
        </div>
      ))}
    </div>
  );
}
```

### Custom trigger

```tsx
import { ActionMenu, Button, Icon } from '@bindshq/stance-react';
import type { ActionMenuItem } from '@bindshq/stance-react';

const signatureActions: ActionMenuItem[] = [
  { label: 'Edit signature', icon: <Icon name="pencil" />, shortcut: '⌘E' },
  { label: 'Duplicate', icon: <Icon name="copy" /> },
  { label: 'Preview in Outlook', icon: <Icon name="eye" /> },
  { type: 'separator' },
  { label: 'Delete', icon: <Icon name="trash" />, destructive: true },
];

export function CustomTrigger() {
  return (
    <ActionMenu
      trigger={
        <Button variant="outline" size="sm" trailingIcon={<Icon name="chevron-down" />}>
          Manage
        </Button>
      }
      items={signatureActions}
    />
  );
}
```

## API reference

| Component | Prop | Type | Default | Description |
| --- | --- | --- | --- | --- |
| ActionMenu | `items` (required) | `ActionMenuItem[]` | None | Actions: `{ label, onSelect, icon, shortcut, destructive, disabled, items }`, `{ type: "separator" }` or `{ type: "group", label, items }`. |
| ActionMenu | `label` | `string` | `'More actions'` | Accessible label of the default trigger. Make it specific in lists. |
| ActionMenu | `trigger` | `ReactElement` | None | Replace the default icon button (rendered with asChild). |
| ActionMenu | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Horizontal or vertical ellipsis icon. |
| ActionMenu | `size` | `'xs' \| 'sm' \| 'md'` | `'sm'` | Size of the default trigger. |
| ActionMenu | `side / align` | `Side / Align` | `'bottom' / 'end'` | Menu placement. |
| ActionMenu | `open / defaultOpen / onOpenChange` | `boolean / function` | None | Open state. |
| ActionMenu | `disabled` | `boolean` | `false` | Disable the trigger. |

## Accessibility

- The default trigger is an IconButton with an accessible name; pass a row-specific label such as “Actions for Ben Hughes”.
- Inherits the complete DropdownMenu keyboard model: arrows, Home/End, typeahead, submenus and Escape.
- Focus returns to the trigger after an action is chosen.

## Keyboard

| Keys | Action |
| --- | --- |
| `Enter` `Space` `ArrowDown` | Open and focus the first action. |
| `ArrowDown` `ArrowUp` | Move between actions. |
| `Enter` | Run the focused action. |
| `Escape` | Close without acting. |

## Guidelines

**Do**

- Show the primary row action inline and put the rest in the ActionMenu.
- Put destructive actions last, after a separator.

**Don’t**

- Hide the only way to perform an important action inside an overflow menu.

## Related

- https://stanceui.com/components/dropdown-menu
- https://stanceui.com/components/icon-button
- https://stanceui.com/components/data-table
