# MenuDropdown

> Slug: `menu-dropdown` · Category: Navigation

## When to use
- A form-field-style dropdown with floating label, supporting text, and error message.
- When the user must pick one or more options from a constrained list inside a form.
- When you need autocomplete/search-as-you-type or freeform text with suggestions.

## When NOT to use
- For a button trigger that opens command menus — use `MenuButton`.
- For a simple native single-select — use `Select`.
- For a single boolean — use `Checkbox` or `Toggle`.

## Variants & decision tree
Two independent axes: **trigger variant** and **menu behavior**.

### `variant` — trigger appearance
- **`'selecting'`** → button trigger that displays selected items. Default for plain dropdowns.
- **`'searching'`** → search input trigger with a clear button (`onClear`). Filter `menuItems` externally as the user types.
- **`'texting'`** → freeform text input with suggestions (combobox).

### `menuBehavior` — selection model
- **`'Single select'`** → one item selectable. The "complete" floating-label state requires a selected item (`selecting`) or non-empty value (`searching`/`texting`).
- **`'Multi select'`** → multiple items toggleable.
- **`'Action items'`** → no selection state; clicking fires `onItemSelect` once.

| Need | variant | menuBehavior |
|---|---|---|
| Pick one country from a list | `selecting` | `Single select` |
| Pick multiple filters | `selecting` | `Multi select` |
| Search a long catalog | `searching` | `Single select` |
| Type with suggestions | `texting` | `Single select` |
| Quick command picker | `selecting` | `Action items` |

## States
Active (focused), Complete (has selection/value), Disabled, Invalid (sets `errorMessage`), Expanded (`expanded` toggles the popup).

## Props
| Prop | Type | Default | Description |
|---|---|---|---|
| `id` | `string` | — | Required; derives label/menu/aria IDs. |
| `label` | `string` | — | Required floating label. |
| `variant` | `'selecting' \| 'searching' \| 'texting'` | — | Required trigger. |
| `menuBehavior` | `'Single select' \| 'Multi select' \| 'Action items'` | — | Selection model. |
| `menuItems` | `MenuItem[]` | — | `{ id, text, icon?, selected?, disabled? }`. |
| `value` | `string` | — | Input value (texting/searching). |
| `expanded` | `boolean` | `false` | Whether the menu is open. |
| `disabled` | `boolean` | `false` | Disable the field. |
| `errorMessage` | `string` | — | Error text — sets invalid state. |
| `supportingText` | `string` | — | Helper text below the field. |
| `inverse` | `boolean` | inherited | Dark-background styling. |
| `onValueChange`, `onItemSelect`, `onClear` | callbacks | — | Behavior hooks. |

## Usage examples
```tsx
<MenuDropdown
  id="country"
  label="Country"
  variant="selecting"
  menuBehavior="Single select"
  expanded={open}
  menuItems={countries}
  onItemSelect={(item) => setCountry(item.id)}
/>
```

## Composition
Internally composes `Menu` with `role="listbox"`. Manage open state with `useMenuDropdown` hook or external state. Pair with form layout patterns from `patterns.md`.

## Accessibility
- The `label` is the floating label and the `aria-labelledby` target — always provide it.
- `errorMessage` is announced via the error region; use it for validation feedback.
- Items must have unique `id` and a non-empty `text`.

## Do / Don't
- Do filter `menuItems` externally for `searching`.
- Do use `Action items` only when you don't want a persistent selection.
- Don't use multi-select with `searching` (treat as single-select).
- Don't omit `errorMessage` when the field is invalid.
