# Menu

Opens a list of actions from a button.

[View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/Menu.tsx)

## Overview

A menu button opens a list of actions. You move through it with the arrow keys and close it with Escape.

Use it for actions and commands. Use `Select` or `Combobox` to choose a form value.

## Examples

### Basic

```tsx
import { Button, Menu, style } from '@tempoxyz/ds'

export function Demo() {
  // The gallery canvas stretches its children, so the wrapper keeps the trigger at its own width.
  return (
    <div {...styles.row()}>
      <Menu.Root>
        <Menu.Trigger render={<Button variant="secondary" />}>Options</Menu.Trigger>
        <Menu.Popup align="start">
          <Menu.Item>
            Edit
            <Menu.Shortcut>⌘E</Menu.Shortcut>
          </Menu.Item>
          <Menu.Item>Duplicate</Menu.Item>
          <Menu.Separator />
          <Menu.Item>Archive</Menu.Item>
        </Menu.Popup>
      </Menu.Root>
    </div>
  )
}

namespace styles {
  export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '3' })
}
```

[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Menu/Basic.tsx)

### Size

Set `size` on `Menu.Popup` to `small`, `medium`, or `large`. It defaults to `medium`.

```tsx
import { Button, Menu, style } from '@tempoxyz/ds'
import { useState } from 'react'

export function Demo() {
  const [density, setDensity] = useState('comfortable')

  // The gallery canvas stretches its children, so the wrapper keeps each trigger at its own width.
  return (
    <div {...styles.row()}>
      {(['small', 'medium', 'large'] as const).map((size) => (
        <Menu.Root key={size}>
          <Menu.Trigger render={<Button size={size} variant="secondary" />}>
            Options ({size})
          </Menu.Trigger>
          <Menu.Popup align="start" size={size}>
            <Menu.Item>
              Edit
              <Menu.Shortcut>⌘E</Menu.Shortcut>
            </Menu.Item>
            <Menu.Item disabled>Duplicate</Menu.Item>
            <Menu.LinkItem href="https://tempo.xyz">Documentation</Menu.LinkItem>
            <Menu.Separator />
            <Menu.CheckboxItem defaultChecked>Show archived</Menu.CheckboxItem>
            <Menu.Group>
              <Menu.GroupLabel>Density</Menu.GroupLabel>
              <Menu.RadioGroup onValueChange={(value) => setDensity(String(value))} value={density}>
                <Menu.RadioItem value="comfortable">Comfortable</Menu.RadioItem>
                <Menu.RadioItem value="compact">Compact</Menu.RadioItem>
              </Menu.RadioGroup>
            </Menu.Group>
            <Menu.Separator />
            <Menu.SubmenuRoot>
              <Menu.SubmenuTrigger>Share</Menu.SubmenuTrigger>
              <Menu.Popup size={size}>
                <Menu.Item>Copy link</Menu.Item>
                <Menu.Item>Email</Menu.Item>
              </Menu.Popup>
            </Menu.SubmenuRoot>
            <Menu.Item intent="negative">Delete</Menu.Item>
          </Menu.Popup>
        </Menu.Root>
      ))}
    </div>
  )
}

namespace styles {
  export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '3' })
}
```

[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Menu/Size.tsx)

### Intent

Set `intent="negative"` on a `Menu.Item` for destructive actions. It defaults to `default`.

```tsx
import { Button, Menu, style } from '@tempoxyz/ds'

export function Demo() {
  // The gallery canvas stretches its children, so the wrapper keeps the trigger at its own width.
  return (
    <div {...styles.row()}>
      <Menu.Root>
        <Menu.Trigger render={<Button variant="secondary" />}>Options</Menu.Trigger>
        <Menu.Popup align="start">
          <Menu.Item>Edit</Menu.Item>
          <Menu.Separator />
          <Menu.Item intent="negative">Delete</Menu.Item>
        </Menu.Popup>
      </Menu.Root>
    </div>
  )
}

namespace styles {
  export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '3' })
}
```

[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Menu/Intent.tsx)

### Disabled

Set `disabled` on a `Menu.Item` to make it unavailable.

```tsx
import { Button, Menu, style } from '@tempoxyz/ds'

export function Demo() {
  // The gallery canvas stretches its children, so the wrapper keeps the trigger at its own width.
  return (
    <div {...styles.row()}>
      <Menu.Root>
        <Menu.Trigger render={<Button variant="secondary" />}>Options</Menu.Trigger>
        <Menu.Popup align="start">
          <Menu.Item>Edit</Menu.Item>
          <Menu.Item disabled>Duplicate</Menu.Item>
        </Menu.Popup>
      </Menu.Root>
    </div>
  )
}

namespace styles {
  export const row = style({ alignItems: 'center', display: 'flex', flexWrap: 'wrap', gap: '3' })
}
```

[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/Menu/Disabled.tsx)

## Guidelines

TODO: Write guidelines for Menu.
