# Menu Button

> Source: https://design.nanatec.co.ke/components/menu-button/
> A button that opens a menu of commands, with the menu keyboard contract rather than a listbox's.

A button that opens a menu. Use it for a list of commands — a profile menu, a
row's actions — where choosing a row *does* something.

:::note
This one ships as a web component only. There is no React or Svelte
implementation yet, so the CLI has nothing to copy for those targets.
:::

## Preview

```html
<nana-menu-button label="Account">
  <nana-menu-item value="settings">Settings</nana-menu-item>
  <nana-menu-item value="billing">Billing</nana-menu-item>
  <nana-menu-item value="signout">Sign out</nana-menu-item>
</nana-menu-button>
```

## Menu or dropdown?

They look alike and behave differently, and picking the wrong one shows up as
surprising keyboard behaviour rather than anything visible.

| | `nana-menu-button` | [`nana-dropdown`](/components/dropdown) |
|---|---|---|
| Pattern | menu | listbox |
| Children | `nana-menu-item` | `nana-option` |
| Choosing a row | runs a command | selects a value and keeps it |
| <kbd>Tab</kbd> | closes it and moves on | closes it and moves on |
| Keeps a selection | no | yes |

A SACCO or account switcher picks a value, so it is a dropdown. A profile menu
runs commands, so it is a menu button.

In both, <kbd>Tab</kbd> leaves rather than cycling inside — that is the pattern
for both, and neither traps focus. Move between rows with the arrow keys.

## Installation

```bash
npm install @nana-tec/ui-components
```

```js
import "@nana-tec/ui-components/menu-button";
```

## A custom trigger

Slot `trigger` to replace the label entirely — an avatar, an icon button,
anything. The slotted content sits inside the real button, so it keeps the
popup semantics.

```html
<nana-menu-button>
  <span slot="trigger">⋯</span>
  <nana-menu-item value="rename">Rename</nana-menu-item>
  <nana-menu-item value="delete">Delete</nana-menu-item>
</nana-menu-button>
```

## Naming the trigger

A trigger that shows only an avatar or an icon has no accessible name, and
neither does one whose label is hidden at narrow widths. `aria-label` reaches
the real button inside:

```html
<nana-menu-button aria-label="Switch account">
  <span slot="trigger">AB</span>
  <nana-menu-item value="one">Nairobi Sacco</nana-menu-item>
  <nana-menu-item value="two">Mombasa Sacco</nana-menu-item>
</nana-menu-button>
```

Without a `label`, an `aria-label` or trigger text, the component warns in the
console rather than shipping an unnamed control.

## Keyboard

| Key | Result |
|---|---|
| <kbd>Enter</kbd> / <kbd>Space</kbd> / <kbd>↓</kbd> | Opens onto the first row |
| <kbd>↑</kbd> | Opens onto the last row |
| <kbd>↑</kbd> / <kbd>↓</kbd> | Moves between rows, wrapping at the ends |
| <kbd>Home</kbd> / <kbd>End</kbd> | Jumps to the first or last row |
| <kbd>Esc</kbd> | Closes it and returns focus to the button |
| <kbd>Tab</kbd> | Closes it and carries on to whatever follows |

Disabled rows are skipped.

## API

## Events

| Event | Type | Description |
|---|---|---|
| `nana-open` | `CustomEvent` | The menu opened. |
| `nana-close` | `CustomEvent` | The menu closed. |
| `nana-select` | `CustomEvent` | Bubbled from a chosen row; `detail.value`. |

## Accessibility

The trigger carries `aria-haspopup="menu"` and `aria-expanded`, and the panel is
a labelled `menu`. Focus moves onto a real row rather than being tracked with
`aria-activedescendant`, which is what separates a menu from a listbox.

## Related components

- [Dropdown](/components/dropdown) — choosing a value rather than running a command
- [Menu](/components/menu) — the rows on their own, without a trigger
- [Menubar](/components/menubar) — several menus along a bar
