Components Navigation
CommandMenu
StableA searchable, keyboard-driven list of commands with groups, keywords and shortcuts.
CommandMenu combines a search field with a filtered list of actions. It is the building block for CommandPalette and can also be embedded inline, for example in an empty state or a sidebar quick-switcher. Filtering uses a built-in fuzzy scorer over each item’s value and keywords; pass your own scorer or disable filtering for server-side search.
Overview
New template⌘N
Browse gallery
Invite user⌘I
Open integrations
Settings⌘,
No results found.
import * as React from 'react';
import { CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandMenu, CommandSeparator, Icon } from '@bindshq/stance-react';
const box: React.CSSProperties = { width: 'min(440px, 100%)' };
export function Basic() {
const [last, setLast] = React.useState('');
return (
<div style={{ ...box, display: 'grid', gap: 8 }}>
<CommandMenu label="Quick actions" onItemSelect={setLast}>
<CommandInput />
<CommandList>
<CommandGroup heading="Templates">
<CommandItem value="New template" icon={<Icon name="plus" />} shortcut="⌘N" />
<CommandItem value="Browse gallery" icon={<Icon name="layout-grid" />} />
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Organisation">
<CommandItem value="Invite user" icon={<Icon name="users" />} shortcut="⌘I" />
<CommandItem value="Open integrations" icon={<Icon name="link" />} />
<CommandItem value="Settings" icon={<Icon name="settings" />} shortcut="⌘," />
</CommandGroup>
</CommandList>
<CommandEmpty />
</CommandMenu>
<span aria-live="polite">{last && `Selected: ${last}`}</span>
</div>
);
}Light, dark and high contrast
Every Stance component is designed and tested in all three appearance modes.
New template⌘N
Browse gallery
Invite user⌘I
Open integrations
Settings⌘,
No results found.
New template⌘N
Browse gallery
Invite user⌘I
Open integrations
Settings⌘,
No results found.
New template⌘N
Browse gallery
Invite user⌘I
Open integrations
Settings⌘,
No results found.
Import
import { CommandMenu, CommandInput, CommandList, CommandGroup, CommandItem, CommandSeparator, CommandEmpty, CommandShortcut } from '@bindshq/stance-react';Examples
Keywords and disabled items
Typing “create” finds “New template”.
New template
Import from Outlook
Export as HTML
No actions match. Try “create” or “download”.
import * as React from 'react';
import { CommandEmpty, CommandInput, CommandItem, CommandList, CommandMenu, Icon } from '@bindshq/stance-react';
const box: React.CSSProperties = { width: 'min(440px, 100%)' };
export function WithKeywords() {
return (
<CommandMenu label="Template actions" style={box}>
<CommandInput placeholder="Search actions…" />
<CommandList>
<CommandItem
value="New template"
keywords={['create', 'add']}
icon={<Icon name="plus" />}
/>
<CommandItem
value="Import from Outlook"
keywords={['upload']}
icon={<Icon name="upload" />}
disabled
/>
<CommandItem
value="Export as HTML"
keywords={['download']}
icon={<Icon name="download" />}
/>
</CommandList>
<CommandEmpty>No actions match. Try “create” or “download”.</CommandEmpty>
</CommandMenu>
);
}Custom filtering
Disable built-in filtering and render your own results.
Ada Lovelace
Grace Hopper
Katherine Johnson
Alan Turing
Margaret Hamilton
No people found.
import * as React from 'react';
import { CommandEmpty, CommandInput, CommandItem, CommandList, CommandMenu, Icon } from '@bindshq/stance-react';
const box: React.CSSProperties = { width: 'min(440px, 100%)' };
const people = [
'Ada Lovelace',
'Grace Hopper',
'Katherine Johnson',
'Alan Turing',
'Margaret Hamilton',
];
export function ServerFiltering() {
const [search, setSearch] = React.useState('');
// Stand-in for a server query: case-insensitive "contains".
const results = people.filter((p) => p.toLowerCase().includes(search.toLowerCase()));
return (
<CommandMenu
label="Find a person"
search={search}
onSearchChange={setSearch}
filter={false}
style={box}
>
<CommandInput placeholder="Search people…" />
<CommandList>
{results.map((p) => (
<CommandItem key={p} value={p} icon={<Icon name="user" />} />
))}
</CommandList>
<CommandEmpty>No people found.</CommandEmpty>
</CommandMenu>
);
}API reference
CommandMenu
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | 'Commands' | Accessible name for the input and listbox. |
search / defaultSearch / onSearchChange | string / string / (search: string) => void | None | Controlled or uncontrolled search text. |
filter | ((text: string, search: string) => number) | false | fuzzyScore | Return 0 to hide an item; false disables filtering. |
onItemSelect | (value: string) => void | None | Called after any item is selected. |
CommandInput
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder | string | 'Type a command or search…' | Input placeholder. |
hideIcon | boolean | false | Hide the search icon. |
CommandList
| Prop | Type | Default | Description |
|---|---|---|---|
...props | HTMLAttributes<HTMLDivElement> | None | The listbox. |
CommandGroup
| Prop | Type | Default | Description |
|---|---|---|---|
heading | ReactNode | None | Group heading and accessible name. Empty groups hide automatically. |
CommandItem
| Prop | Type | Default | Description |
|---|---|---|---|
value* required | string | None | Unique value used for filtering and passed to onSelect. |
keywords | string[] | None | Extra search terms. |
onSelect | (value: string) => void | None | Runs on click or Enter. |
icon / shortcut | ReactNode | None | Leading icon and trailing shortcut hint. |
disabled | boolean | false | Visible but not selectable; skipped by arrow keys. |
forceMount | boolean | false | Always render regardless of the search. |
CommandEmpty
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | 'No results found.' | Shown and announced when nothing matches. Place after CommandList. |
Accessibility
- Follows the WAI-ARIA combobox pattern: the input has role="combobox" with aria-controls and aria-activedescendant pointing at the highlighted option.
- Focus stays in the input; arrow keys move the highlight, so typing is never interrupted.
- Groups are role="group" named by their heading; separators are hidden from assistive technology.
- The empty message lives in a polite status region.
Keyboard
| Keys | Action |
|---|---|
| ↓ ↑ | Move the highlight, wrapping at the ends and skipping disabled items. |
| PageUp PageDown | Jump to the first or last item. |
| Enter | Run the highlighted command. |
Usage guidelines
Do
- Name commands as verbs: “Invite user”, “Open integrations”.
- Add keywords for synonyms people actually type.
Don’t
- Put more than ~50 items in one group without search hints.