Skip to content
v0.2.10

Menu

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

Preview

Use Menu

Menu is a named export of @flood-md/react. Connect the package once, then import what you use.

First time here? Connect Flood
Example import style
menu.tsxTSX
"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

PropValuesDefault
labelstringRequired
trigger(props: OverlayTriggerProps) => ReactNodeRequired
itemsreadonly MenuItem[]Required
onAction(id: string) => void—
openboolean—
defaultOpenbooleanfalse
onOpenChange(open: boolean) => void—
disabledbooleanfalse
side"top" | "bottom" | "left" | "right""bottom"
align"start" | "center" | "end""start"
controlSize"sm" | "md" | "lg" | "xl""sm"
Native HTML propsOmit<HTMLAttributes<HTMLDivElement>, "children" | "role">Forwarded
View TypeScript source