CommandMenu
Search and quick actions: a search field that filters a list of commands, grouped under headings. In the page, or as a modal dialog opened from a trigger.
Usage
Import the component and render it.
import { CommandMenu } from 'src/components/CommandMenu/CommandMenu';
import { Button } from 'src/components/Button/Button';
import { CalendarBlankIcon, SmileyIcon, CalculatorIcon, UserIcon, CreditCardIcon, GearIcon } from '@phosphor-icons/react';
<CommandMenu
groups={[{"heading":"Suggestions","items":[{"label":"Calendar","icon":<CalendarBlankIcon />},{"label":"Search Emoji","icon":<SmileyIcon />},{"label":"Calculator","icon":<CalculatorIcon />,"disabled":true}]},{"heading":"Settings","items":[{"label":"Profile","icon":<UserIcon />,"shortcut":"⌘P"},{"label":"Billing","icon":<CreditCardIcon />,"shortcut":"⌘B"},{"label":"Settings","icon":<GearIcon />,"shortcut":"⌘S"}]}]}
placeholder="Type a command or search…"
trigger={<Button variant="outline" size="sm">Open command menu</Button>}
/>Accessibility
Role: a search <input role="combobox" aria-autocomplete="list"> controlling a role="listbox" of options in named groups; modal: a <dialog> named by the label.
| Key | Action |
|---|---|
| Typing | Filters the commands; the first enabled match is highlighted |
| ↓ / ↑ | Highlights the next / previous match (disabled ones are skipped; focus stays in the search field) |
| Home / End | Highlights the first / last match |
| Enter | Runs the highlighted command (and closes the modal menu) |
| Escape | Modal: closes it, and focus returns to the trigger. In the page: clears the search |
- The search field is named by the label (there is no visible label, as in Figma); the placeholder is not its name.
- When nothing matches, the empty message is a live status (announced), not an option.
- A click runs a command; the pointer does not move the highlight (Hover is its own state).
- The Separators are decorative (hidden from assistive technology); each group is named by its heading.
Results
Results only changes the content: each example passes its own props.
<CommandMenu groups={[{"heading":"Suggestions","items":[{"label":"Calendar","icon":<CalendarBlankIcon />},{"label":"Search Emoji","icon":<SmileyIcon />},{"label":"Calculator","icon":<CalculatorIcon />,"disabled":true}]},{"heading":"Settings","items":[{"label":"Profile","icon":<UserIcon />,"shortcut":"⌘P"},{"label":"Billing","icon":<CreditCardIcon />,"shortcut":"⌘B"},{"label":"Settings","icon":<GearIcon />,"shortcut":"⌘S"}]}]} />
<CommandMenu
groups={[{"heading":"Suggestions","items":[{"label":"Calendar","icon":<CalendarBlankIcon />},{"label":"Search Emoji","icon":<SmileyIcon />},{"label":"Calculator","icon":<CalculatorIcon />,"disabled":true}]},{"heading":"Settings","items":[{"label":"Profile","icon":<UserIcon />,"shortcut":"⌘P"},{"label":"Billing","icon":<CreditCardIcon />,"shortcut":"⌘B"},{"label":"Settings","icon":<GearIcon />,"shortcut":"⌘S"}]}]}
query="Unknown command"
/>Composition
Use the following composition to build a CommandMenu:
CommandMenu
├── CommandMenuItem
├── Input
└── SeparatorCommandMenuItem
One result of a Command Menu: an optional icon, a label and an optional keyboard shortcut. Only used inside CommandMenu.
<CommandMenuItem label="Command" />Actions
Pass callbacks to respond to the component.
import { CommandMenu } from 'src/components/CommandMenu/CommandMenu';
import { Button } from 'src/components/Button/Button';
import { CalendarBlankIcon, SmileyIcon, CalculatorIcon, UserIcon, CreditCardIcon, GearIcon } from '@phosphor-icons/react';
<CommandMenu
groups={[{"heading":"Suggestions","items":[{"label":"Calendar","icon":<CalendarBlankIcon />},{"label":"Search Emoji","icon":<SmileyIcon />},{"label":"Calculator","icon":<CalculatorIcon />,"disabled":true}]},{"heading":"Settings","items":[{"label":"Profile","icon":<UserIcon />,"shortcut":"⌘P"},{"label":"Billing","icon":<CreditCardIcon />,"shortcut":"⌘B"},{"label":"Settings","icon":<GearIcon />,"shortcut":"⌘S"}]}]}
placeholder="Type a command or search…"
trigger={<Button variant="outline" size="sm">Open command menu</Button>}
onQueryChange={(query) => console.log(query)}
onOpenChange={(open) => console.log(open)}
/>| Callback | When |
|---|---|
onQueryChange | Called as the search text changes. |
onOpenChange | Called when the modal menu opens or closes (trigger, running an item, Esc, a click outside). |
