Skip to content
Work in progress - do not use in production. This component is still being built: it is not flagged Ready for Dev, so its markup, attributes, events and styles can all still change without notice, it is not covered by the accessibility gate, and it is not published to npm. It is on this site so the work can be seen and reviewed - nothing more.

CommandPalette

A modal command launcher built on the native <dialog>: <dialog is="root-command-palette">.

Usage

  • New file
  • Open file…
  • Save
  • Settings
  • New file
  • Open file…
  • Save
  • Settings
<dialog is="root-command-palette" open aria-label="Command palette">
  <input type="search" placeholder="Type a command…" />
  <ul>
    <li data-command="new-file">New file</li>
    <li data-command="open-file" data-keywords="recent">Open file…</li>
    <li data-command="save" data-keywords="write disk">Save</li>
    <li data-command="settings" data-keywords="preferences config">Settings</li>
  </ul>
</dialog>

Open it from a trigger with palette.reveal():

document.querySelector('[data-open-palette]')
  .addEventListener('click', () => palette.reveal());

palette.addEventListener('root-command-palette.command', (event) => {
  runCommand(event.detail.command);
});

Author markup is just a search <input> and a <ul> of <li data-command="…"> items; the component wires the combobox/listbox ARIA relationship, injects any missing input/list, and gives each item a stable id and role="option". Typing filters the items (matching the visible text plus an optional data-keywords), the arrow keys move an aria-activedescendant highlight (wrapping at the ends), Home/End jump to the first/last match, and Enter or a click runs the highlighted command. A polite live region announces the match count.

reveal() opens the palette as a native modal (top layer, focus trap, and Escape-to-close come for free) and clears any previous filter; close() is the unchanged native <dialog> method.

Properties

Property Type Description
options HTMLLIElement[] (read-only) All command items
visibleOptions HTMLLIElement[] (read-only) Items passing the current filter

Methods

Method Description
reveal() Open as a modal and reset the filter
close() Native <dialog> close (unchanged)
filter(query) Filter items by text and data-keywords
resetFilter() Clear the filter and reveal every item
move(delta) Move the highlight (+1 / -1), wrapping
select(li) Run a command and close

Item attributes

Attribute On Description
data-command <li> The command id emitted on select
data-keywords <li> Extra space-separated search terms

Events

Event Detail Description
root-command-palette.command { command, label } Fired when a command is chosen (before close)

Accessibility

A backdrop click closes the palette (clicks on the input/list don't). Page scroll is locked for as long as any modal <dialog> is open (foundations/_reset.css).

Extends

HTMLDialogElement - use with <dialog is="root-command-palette">.