# Menu

An action and preference menu with keyboard navigation and controlled checkbox/radio items.

Connect Flood once using [the installation guide](https://flood.md/docs/installation). Then import the components you use; no per-component add command is needed.

## Example

```tsx
"use client";

import { FloodRoot, Menu, Button } from "@flood-md/react";
import "@flood-md/react/styles.css";

export function Example() {
  return (
    <FloodRoot>
      <Menu label="Project actions"
        trigger={props => <Button {...props}>Project actions</Button>}
        items={[{id:"rename",label:"Rename…"},{id:"divider",type:"separator"},{id:"delete",label:"Delete project",tone:"danger"}]}
        onAction={id => console.log(id)}
      />
    </FloodRoot>
  );
}
```

## Design notes

- Forward all supplied trigger props and ref to one native button or Flood Button/IconButton. Label names the menu; action labels remain visible.
- Enter/Space and ArrowDown open at the first item; ArrowUp opens at the last. Inside use arrows, Home/End and label-prefix typeahead.
- Disabled items stay keyboard-focusable with aria-disabled but cannot activate. Separators are noninteractive; action IDs must be unique and nonempty. At least one action is required.
- Escape closes and restores trigger focus. Tab moves to the next control after the trigger; Shift+Tab returns to the trigger. Outside interaction dismisses without stealing deliberately moved focus.
- Shortcut text is a visual hint, not an implemented key binding. No href or asynchronous task manager is included. Nested items use type="submenu" and a nonempty items array. Checkbox/radio items are controlled preferences, available in 0.2.7.
- Controlled open needs host updates; onAction requests closure before calling the host. Modern native Popover API required. Native div props/ref target the popup. Available in 0.2.4.
- Checkbox items take checked (boolean or mixed) and onCheckedChange. Radio items take a nonempty group label, checked and onCheckedChange; the host keeps one selected item per group. Keep each radio group contiguous. Preference items stay open by default; closeOnSelect opts into dismissal. They do not call onAction or submit form values.
- Submenus open by logical arrow, click/tap or cancellable mouse hover intent. Escape closes one level; Tab leaves the entire tree through the root trigger. IDs are unique across the tree and nested keyboard searches stay inside their own menu.

## API reference

| Prop | Values | Default |
| --- | --- | --- |
| `label` | `string` | `Required` |
| `trigger` | `(props: OverlayTriggerProps) => ReactNode` | `Required` |
| `items` | `readonly MenuItem[]` | `Required` |
| `onAction` | `(id: string) => void` | `—` |
| `open` | `boolean` | `—` |
| `defaultOpen` | `boolean` | `false` |
| `onOpenChange` | `(open: boolean) => void` | `—` |
| `disabled` | `boolean` | `false` |
| `side` | `"top" \| "bottom" \| "left" \| "right"` | `"bottom"` |
| `align` | `"start" \| "center" \| "end"` | `"start"` |
| `controlSize` | `"sm" \| "md" \| "lg" \| "xl"` | `"sm"` |
| `Native HTML props` | `Omit<HTMLAttributes<HTMLDivElement>, "children" \| "role">` | `Forwarded` |
