Command
A command palette (⌘K to invoke, hotkey configurable) — search filtering, score-based ranking, keyboard selection, Enter to execute, nested sub-pages, recent history and multi-select batch run. open is controlled: it can be set externally, and the configurable global shortcut or Esc closes it (each open/close fires one oas-open-change).
Basic usage
Basic usage (open with ⌘K / Ctrl+K)
Controlled open
The open attribute is externally controlled: an external button sets open to open the palette; it closes via Esc / backdrop click / selecting a command (the component removes open; the host syncs state through oas-open-change).
When open, the backdrop covers the full screen, so no external "close" button is provided — use Esc / click the backdrop / select a command to close.
Externally controlled open (sync via oas-open-change)
Groups and empty state
Group titles render from the group field; an empty state shows when nothing matches (plain "No matching commands" when the query is empty, or "No commands found for "word"" with a search term).
Groups and empty state
Icons · descriptions · shortcut labels
Item fields icon (SVG path d or a full <svg> markup), description (secondary line) and shortcut (right-aligned kbd with meta/ctrl/shift/alt symbol mapping).
Icon + description + shortcut
Configurable invocation shortcut
The hotkey attribute configures the combo (mod/meta/ctrl/alt/shift, comma-separated for multiple); false disables the built-in listener. Default is mod+k (⌘K / Ctrl+K).
Custom shortcut (ctrl+shift+p) and disabled
Match highlighting
While searching, the matched characters in the label are wrapped in <mark> — instant feedback as you type.
Search highlight
External filtering (should-filter=false)
should-filter="false" disables built-in filtering and ranking — filtering is fully delegated to the host: the component fires oas-input as you type, and the host requests an async data source and writes back items. This demo simulates a 600ms server search; when there are no results it returns a forceMount "create" entry (rendered regardless of filtering).
should-filter=false + async data source
Empty-state slot
slot="empty" customizes the empty result rendering (replacing the default "No commands found…" text); the host reads the current query via el.query. Example: a "create xxx" button when nothing matches.
Empty-state slot
Nested pages / breadcrumb fallback
The item field page (array of commands) defines a sub-page: selecting it enters the sub-page (a breadcrumb bar with a back button appears at the top), Esc or Backspace with an empty query goes back, and only at the root does Esc close the panel. Each push/pop fires one oas-page-change.
Nested pages
Recent history
recent tracks recently used commands: selected items are pinned to the top (deduped, capped at 10); recent-storage-key enables localStorage persistence (restored across instances). This demo swaps the item set after selection to simulate "command set changes" — reopen to see the "Recent" group.
Recent history (localStorage persistence)
Loading and limit
loading shows an async loading placeholder (spinner row + aria-busy); limit caps the rendered item count (default 50).
Loading and limit
Multiple-select commands
multiple mode: Enter/click toggles checks (fires oas-change { values }), and a "Run n" confirm button in the footer executes the batch (fires oas-select { values }).
Multi-select batch run
In-panel views (Raycast style)
The item field view defines a view: selecting it renders the form/panel carried by <slot name="view-{view}"> (deploy params, quick actions…), Esc/breadcrumb goes back. Each enter/exit fires one oas-view-change.
View slot (deploy form)
Controlled query and active item
value is the controlled search query (two-way by echoing oas-input back); selected is the controlled active item (the host echoes oas-active back). close-on-select="false" keeps the panel open after selection for consecutive actions.
Controlled value / selected
Custom footer
slot="footer" replaces the default shortcut hints (↑↓ navigate / ↵ select / esc close).
Footer slot
Virtual scrolling
virtual enables windowed rendering for large datasets (reuses oas-virtual-list; falls back to full rendering when groups or recents are present). This demo preloads 20,000 commands and renders only the visible window.
Virtual scrolling (20k items)
API
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
close-on-select | Close the panel after selecting (default true; false keeps it open for consecutive actions) | string | — |
hotkey | Invocation shortcut combos, e.g. ctrl+k / meta+shift+p (comma-separated for multiple; supports mod/meta/ctrl/alt/shift); false disables the built-in listener (default mod+k) | string | mod+k |
item-height | Virtual row height (default 36) | string | 36 |
items | Command items JSON (root page; sub-pages via item.page, supports icon / shortcut / description / page / view / forceMount / separator fields) | CommandItem[] | string | [] |
limit | Max rendered items (default 50; not applied in virtual mode) | string | 50 |
loading | Async loading placeholder (loading row in the list + aria-busy) | boolean | — |
multiple | Multiple-select mode (toggle checks + batch run via the footer confirm button) | boolean | — |
open | Whether open (controlled; auto-removed after selection / Esc; fires oas-open-change on open and close) | boolean | — |
recent | Track recently used (selected items pinned to top, deduped, capped at 10) | boolean | — |
recent-storage-key | localStorage key for recent persistence (requires recent; restored across instances) | string | — |
selected | Active item value (controlled; arrow keys / hover fire oas-active for the host to echo back) | string | — |
should-filter | false disables built-in filtering and score sorting (filtering delegated to the host, for async/server data sources) | string | true |
value | Search query (controlled; two-way via oas-input echo-back) | string | — |
virtual | Virtual scrolling for large datasets (reuses oas-virtual-list) | boolean | — |
Events
| Event | Description |
|---|---|
oas-active | Active item changed, detail: { value } (basis for controlled selected echo-back) |
oas-change | Multi-select toggle, detail: { values } |
oas-input | Search input, detail: { value } (request channel for should-filter=false external filtering) |
oas-open-change | Panel opened/closed, detail: { open } |
oas-page-change | Sub-page pushed/popped, detail: { title, depth, direction } (direction: push|pop) |
oas-select | A command was executed, detail: { value }; multi-select confirm detail: { values } |
oas-view-change | View entered/exited, detail: { view, title } (exiting sends view: '') |
Slots
| Name | Description |
|---|---|
empty | Custom empty state (read the current query via el.query, e.g. a "create xyz" entry) |
footer | Custom footer bar (defaults to ↑↓ navigate / ↵ select / esc close hints) |
CommandItem fields:
| Field | Description | Type |
|---|---|---|
label | Display text | string |
value | Selected value (oas-select detail.value) | string |
keywords | Search keywords (optional), matched in addition to the label | string[] |
group | Group name (optional); same-group items render a group title | string |
disabled | Disables the item (not selectable via Enter/click, skipped by arrow keys) | boolean |
Keyboard: ↑/↓ move the highlight (skipping disabled items), Enter executes and closes (multi-select toggles checks), Esc closes (sub-pages pop first), Backspace with an empty query pops a sub-page, Tab cycles between the search input and the options (focus trap); on open the search input is focused, and on close focus returns to the source element. The global shortcut defaults to ⌘K / Ctrl+K (hotkey is configurable or can be disabled).