Menus
Command menu components, behavior, and when to use each.
Menus are the presentation layer for command arrays. They all receive data, optional meta, and commands.
Shared contract
All menus follow the same pattern:
<SomeCommandMenu
data={rowOrContextData}
meta={optionalMeta}
commands={taskCommands.pick({ updateStatus: true, delete: true }).toArray()}
/>data: validated by each command's.input(...)meta: optional additional context for meta-aware builderscommands: array output from.pick(...).toArray()or.omit(...).toArray()
Menus also accept command lifecycle props:
onSuccess: called after a command mutation succeedsonError: called after a command mutation failsonSettled: called after success or errorfallback: rendered when an individual command is filtered out by schema, conditions, or permission
DropdownCommandMenu closes itself after onSuccess runs.
InlineCommandMenu
Best for visible actions in headers/toolbars and desktop detail views.
Behavior:
- renders actions as inline controls/buttons
- good for primary, high-frequency actions
<InlineCommandMenu data={null} commands={projectCommands.pick({ create: true }).toArray()} />Loading state:
<InlineCommandMenuLoading />DropdownCommandMenu
Best when horizontal space is limited or actions are secondary.
Behavior:
- renders a compact "more" trigger
- opens a dropdown list of commands
<DropdownCommandMenu
data={task}
commands={taskCommands.pick({ updateStatus: true, updateAssignee: true, delete: true }).toArray()}
/>Loading state:
<DropdownCommandMenuLoading />ContextCommandMenu + ContextCommandMenuContent
Best for right-click interactions on rows/cards.
Behavior:
- opens on context trigger (right click / long press depending platform)
- supports empty state label when the
commandsarray is empty
<ContextCommandMenu>
<ContextCommandMenuTrigger>...</ContextCommandMenuTrigger>
<ContextCommandMenuContent
data={row}
commands={customerCommands.pick({ delete: true }).toArray()}
emptyLabel="Geen acties beschikbaar"
/>
</ContextCommandMenu>FloatingCommandMenu
Best for bulk selection action bars in tables.
Behavior:
- fixed floating action bar
- explicit
statecontrols visibility (open/closed) - usually used with selected rows array as
data - supports empty state label when the
commandsarray is empty
<FloatingCommandMenu
state={selected.length > 0 ? "open" : "closed"}
data={selected}
commands={taskCommands.pick({ updateStatus: true, delete: true }).toArray()}
/>ResponsiveCommandMenu
Best default for detail topbars when you want desktop/mobile behavior out of the box.
Behavior:
- desktop: inline command menu
- mobile/tablet: dropdown command menu
<ResponsiveCommandMenu
data={project}
commands={projectCommands.pick({ updateStatus: true, archive: true, restore: true, delete: true }).toArray()}
/>Loading state:
<ResponsiveCommandMenuLoading />Empty states and filtered commands
Menu empty states only check the command array passed into the menu. They do not know whether every individual command later failed schema validation, conditions, or permission checks.
If a command should leave a visible placeholder when it is filtered out, pass a plain React node as fallback. The fallback is not rendered inside command context, so do not use command primitives there.
<ContextCommandMenuContent
data={row}
fallback={<span className="px-2 py-1.5 text-muted-foreground text-sm">Geen acties beschikbaar</span>}
commands={customerCommands.pick({ delete: true }).toArray()}
/>Choosing the right menu
- use
InlineCommandMenufor immediate visibility - use
DropdownCommandMenufor compact layouts - use
ContextCommandMenufor row/card context actions - use
FloatingCommandMenufor bulk actions - use
ResponsiveCommandMenufor adaptive topbar actions