# Menu

> A list of actions opened from a button.

## Examples

### Basic

`{ separator: true }` in `items` draws a line between groups.

```vue
<script setup lang="ts">
const toast = useToast();

const items = [
  { label: "Edit", value: "edit", hint: "E" },
  { label: "Duplicate", value: "duplicate", hint: "D" },
  { label: "Archive", value: "archive", disabled: true },
  { separator: true as const },
  { label: "Delete", value: "delete", hint: "⌫" },
];
</script>

<template>
  <UiMenu :items="items" label="Actions" @select="(value) => toast.info(`Selected ${value}`)" />
</template>
```

### Custom trigger

Bind the slot's `attrs` to your own button.

```vue
<script setup lang="ts">
const toast = useToast();
const items = [
  { label: "Profile", value: "profile" },
  { label: "Billing", value: "billing" },
  { label: "Sign out", value: "sign-out" },
];
</script>

<template>
  <UiMenu :items="items" label="Account" align="end" @select="(value) => toast.info(value)">
    <template #trigger="{ attrs }">
      <UiIconButton label="Account menu" variant="secondary" v-bind="attrs">
        <Icon name="more" />
      </UiIconButton>
    </template>
  </UiMenu>
</template>
```

## API

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `MenuEntry<T>[]` | `[]` | Menu items in order; `{ separator: true }` draws a line between groups. |
| `label` | `string` | — | Trigger text for the default trigger, and the menu's accessible name. Defaults to the `menu` translation. |
| `align` | `"end" \| "start"` | `"start"` | Which trigger edge the menu lines up with. Flips automatically near the viewport edge. |
| `open` | `boolean` | `false` | Whether the menu is open. |

| Event | Payload | Description |
| --- | --- | --- |
| `select` | `[value: T]` | An item was activated. |
| `update:open` | `[value: boolean]` | `v-model:open` update. |

| Slot | Props | Description |
| --- | --- | --- |
| `trigger` | `{ isOpen: boolean; attrs: Record<string, unknown>; }` | Custom trigger. Bind `attrs` to a `<button>`. |
| `item` | `{ item: MenuItem<T>; active: boolean; }` | Item content. |

Types:

```ts
export type MenuEntry<T extends SelectValue = SelectValue> = MenuItem<T> | MenuSeparator;

export interface MenuItem<T extends SelectValue = SelectValue> extends SelectOption<T> {
  /** Trailing text, e.g. a shortcut like "⌘S". Render richer content via the `item` slot. */
  hint?: string;
}

export type SelectValue = string | number;

/** A line between groups of menu items. */
export interface MenuSeparator {
  separator: true;
}

export interface SelectOption<T extends SelectValue = SelectValue> {
  label: string;
  value: T;
  disabled?: boolean;
}
```

## Styling

- Parts (`[data-part="…"]`): `menu`, `menu-trigger`, `menu-list`, `menu-separator`, `menu-item`, `menu-item-label`, `menu-item-hint`
- State attributes: `data-menu-open`, `data-menu-align`, `data-menu-index`, `data-menu-active`

## Keyboard

| Keys                    | Action                                             |
| ----------------------- | -------------------------------------------------- |
| `Enter` / `Space` / `↓` | Open and focus the first item                      |
| `↑`                     | Open and focus the last item                       |
| `↓` / `↑`               | Move between items, skipping disabled ones         |
| `Home` / `End`          | First / last item                                  |
| Letters                 | Jump to an item by label; repeat a letter to cycle |
| `Escape`                | Close and return focus to the trigger              |
| `Tab`                   | Close and move on                                  |
