Skip to content
Español

Navigate

Type to search. Press Escape to close.

    Components · js

    Command palette

    A modal search for actions. Press Ctrl+K (or +K, or / outside a text field) and type: the list filters by label and keywords, groups without matches disappear, arrows move the highlight and Enter follows the link or runs the action. Items are served as plain links and buttons inside a dialog, so everything the palette can do also exists elsewhere on the page. The component composes the dialog, adds the listbox semantics, the shortcuts, the filtering, an optional list of recent actions and an API to add actions at runtime.

    CSS: css/components/command.css (in ivolt.css). JS: @intervolutions/ivolt/command or auto.js. Added in v0.5.

    The palette, open on Ctrl+Kfixtures/command/basic.htmlOpen alone — The palette, open on Ctrl+K
    <p class="iv-u-m-0" id="cmd-note">Demo palette. The four page links point back to this note instead of a real
    page, the three actions only emit <code>iv:command</code> and change nothing, and every destination of the panel is
    also reachable from the normal navigation of the page: the palette is a shortcut, never the only route. Press
    <kbd>Ctrl</kbd> + <kbd>K</kbd>, <kbd>⌘</kbd> + <kbd>K</kbd> or <kbd>/</kbd> to open it.</p>
    
    <button class="iv-button iv-button--secondary" data-iv-open="cmd" hidden aria-keyshortcuts="Control+K Meta+K">Open the command palette</button>
    
    <dialog class="iv-dialog iv-command" id="cmd" data-iv-component="command" aria-label="Command palette">
      <div class="iv-dialog__panel">
        <div class="iv-command__field">
          <label class="iv-u-sr-only" for="cmd-q">Search actions</label>
          <input class="iv-input iv-command__input" id="cmd-q" type="search" autocomplete="off" placeholder="Type a command or search…">
        </div>
        <nav class="iv-command__groups">
          <section class="iv-command__group" data-iv-group="Pages">
            <h3 class="iv-command__heading">Pages</h3>
            <ul class="iv-command__list">
              <li>
                <a class="iv-command__item" href="#cmd-note" data-iv-keywords="install setup start">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
                  <span class="iv-command__label">Getting started</span>
                  <kbd class="iv-command__kbd">G S</kbd>
                </a>
              </li>
              <li>
                <a class="iv-command__item" href="#cmd-note" data-iv-keywords="button card dialog widgets">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z"/></svg></span>
                  <span class="iv-command__label">Components</span>
                </a>
              </li>
              <li>
                <a class="iv-command__item" href="#cmd-note" data-iv-keywords="colour palette spacing variables">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="8"/><path d="M12 4v16"/></svg></span>
                  <span class="iv-command__label">Design tokens</span>
                </a>
              </li>
              <li>
                <a class="iv-command__item" href="#cmd-note" data-iv-keywords="releases versions news">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M8 6h12M8 12h12M8 18h12M4 6h.01M4 12h.01M4 18h.01"/></svg></span>
                  <span class="iv-command__label">Changelog</span>
                </a>
              </li>
            </ul>
          </section>
          <section class="iv-command__group" data-iv-group="Actions">
            <h3 class="iv-command__heading">Actions</h3>
            <ul class="iv-command__list">
              <li>
                <button class="iv-command__item" type="button" data-iv-command="toggle-theme" data-iv-keywords="dark light appearance">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"><path d="M20 14a8 8 0 1 1-10-10 7 7 0 0 0 10 10z"/></svg></span>
                  <span class="iv-command__label">Toggle theme</span>
                </button>
              </li>
              <li>
                <button class="iv-command__item" type="button" data-iv-command="copy-link" data-iv-keywords="url share clipboard">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M10 14a4 4 0 0 0 6 .5l2-2a4 4 0 0 0-6-6l-1 1"/><path d="M14 10a4 4 0 0 0-6-.5l-2 2a4 4 0 0 0 6 6l1-1"/></svg></span>
                  <span class="iv-command__label">Copy page link</span>
                </button>
              </li>
              <li>
                <button class="iv-command__item" type="button" data-iv-command="print-page" data-iv-keywords="paper pdf export">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"><path d="M7 9V4h10v5M7 18H5v-6h14v6h-2M8 14h8v6H8z"/></svg></span>
                  <span class="iv-command__label">Print this page</span>
                </button>
              </li>
            </ul>
          </section>
          <section class="iv-command__group" data-iv-group="Help">
            <h3 class="iv-command__heading">Help</h3>
            <ul class="iv-command__list">
              <li>
                <a class="iv-command__item" href="#cmd-note" data-iv-keywords="keyboard keys accessibility">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M3 6h18v12H3zM7 10h.01M11 10h.01M15 10h.01M8 14h8"/></svg></span>
                  <span class="iv-command__label">Shortcuts</span>
                  <kbd class="iv-command__kbd">?</kbd>
                </a>
              </li>
              <li>
                <a class="iv-command__item" href="#cmd-note" data-iv-keywords="contact question feedback">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><path d="M12 17h.01M9.5 9.5a2.5 2.5 0 1 1 3 3.5V14"/></svg></span>
                  <span class="iv-command__label">Ask for support</span>
                </a>
              </li>
            </ul>
          </section>
        </nav>
        <p class="iv-command__empty" hidden>No results</p>
        <footer class="iv-command__hints" aria-hidden="true"><kbd>↑↓</kbd> navigate <kbd>↵</kbd> open <kbd>esc</kbd> close</footer>
      </div>
    </dialog>
    // data-iv-component="command"
    {
      open: "cmd",
      group: "Pages",
      keywords: "install setup start",
      command: "toggle-theme",
    }

    Glass variant, recent items, no slash shortcut

    Glass variant with recent itemsfixtures/command/glass.htmlOpen alone — Glass variant with recent items
    <p class="iv-u-m-0" id="cmd-glass-note">Glass palette with recent commands. Demo only: the page links point back to
    this note, the two actions emit <code>iv:command</code> and nothing else, and the same destinations are part of the
    normal navigation of the page. What you activate is kept in <code>localStorage</code> under
    <code>iv-command-recent</code> and comes back as a “Recent” group the next time the palette opens with an empty
    search. <kbd>/</kbd> is switched off here; <kbd>Ctrl</kbd> + <kbd>K</kbd> and <kbd>⌘</kbd> + <kbd>K</kbd> still open it.</p>
    
    <button class="iv-button iv-button--secondary" data-iv-open="cmd-glass" hidden aria-keyshortcuts="Control+K Meta+K">Open the command palette</button>
    
    <dialog class="iv-dialog iv-command iv-command--glass" id="cmd-glass" data-iv-component="command" data-iv-remember="true" data-iv-slash="false" aria-label="Command palette">
      <div class="iv-dialog__panel">
        <div class="iv-command__field">
          <label class="iv-u-sr-only" for="cmd-glass-q">Search actions</label>
          <input class="iv-input iv-command__input" id="cmd-glass-q" type="search" autocomplete="off" placeholder="Type a command or search…">
        </div>
        <nav class="iv-command__groups">
          <section class="iv-command__group" data-iv-group="Pages">
            <h3 class="iv-command__heading">Pages</h3>
            <ul class="iv-command__list">
              <li>
                <a class="iv-command__item" href="#cmd-glass-note" data-iv-keywords="install setup start">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
                  <span class="iv-command__label">Getting started</span>
                  <kbd class="iv-command__kbd">G S</kbd>
                </a>
              </li>
              <li>
                <a class="iv-command__item" href="#cmd-glass-note" data-iv-keywords="button card dialog widgets">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z"/></svg></span>
                  <span class="iv-command__label">Components</span>
                </a>
              </li>
              <li>
                <a class="iv-command__item" href="#cmd-glass-note" data-iv-keywords="colour palette spacing variables">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="8"/><path d="M12 4v16"/></svg></span>
                  <span class="iv-command__label">Design tokens</span>
                </a>
              </li>
            </ul>
          </section>
          <section class="iv-command__group" data-iv-group="Actions">
            <h3 class="iv-command__heading">Actions</h3>
            <ul class="iv-command__list">
              <li>
                <button class="iv-command__item" type="button" data-iv-command="toggle-theme" data-iv-keywords="dark light appearance">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"><path d="M20 14a8 8 0 1 1-10-10 7 7 0 0 0 10 10z"/></svg></span>
                  <span class="iv-command__label">Toggle theme</span>
                </button>
              </li>
              <li>
                <button class="iv-command__item" type="button" data-iv-command="copy-link" data-iv-keywords="url share clipboard">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M10 14a4 4 0 0 0 6 .5l2-2a4 4 0 0 0-6-6l-1 1"/><path d="M14 10a4 4 0 0 0-6-.5l-2 2a4 4 0 0 0 6 6l1-1"/></svg></span>
                  <span class="iv-command__label">Copy page link</span>
                </button>
              </li>
            </ul>
          </section>
          <section class="iv-command__group" data-iv-group="Help">
            <h3 class="iv-command__heading">Help</h3>
            <ul class="iv-command__list">
              <li>
                <a class="iv-command__item" href="#cmd-glass-note" data-iv-keywords="keyboard keys accessibility">
                  <span class="iv-command__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M3 6h18v12H3zM7 10h.01M11 10h.01M15 10h.01M8 14h8"/></svg></span>
                  <span class="iv-command__label">Shortcuts</span>
                  <kbd class="iv-command__kbd">?</kbd>
                </a>
              </li>
            </ul>
          </section>
        </nav>
        <p class="iv-command__empty" hidden>No results</p>
        <footer class="iv-command__hints" aria-hidden="true"><kbd>↑↓</kbd> navigate <kbd>↵</kbd> open <kbd>esc</kbd> close</footer>
      </div>
    </dialog>
    // data-iv-component="command"
    {
      open: "cmd-glass",
      remember: true,
      slash: false,
      group: "Pages",
      keywords: "install setup start",
      command: "toggle-theme",
    }

    Options

    OptionAttributeDefaultEffect
    shortcutdata-iv-shortcuttrueGlobal Ctrl+K / +K.
    slashdata-iv-slashtrue/ opens the palette when focus is not in an editable field.
    rememberdata-iv-rememberfalseKeep the last activated items in local storage and show them as a Recent group.
    maxRecentdata-iv-max-recent5How many recent items to keep.
    recentText, emptyText, placeholderdata-iv-recent-textRecent, No resultsTexts of the generated group, the empty state and the input.

    Methods and events

    open(), close(), add(action), remove(id), clear(), filter(query), destroy(); read isOpen, query and actions. An action is { id, label, group, keywords, href?, shortcut?, run? }. Events on the dialog: the dialog's own iv:open/iv:close; iv:command (cancelable, detail.id, label, item) then iv:commanded; iv:filter with query and visible.

    Keyboard and assistive technology

    The palette is a modal dialog with a name; the input is a combobox whose listbox is the action list, the highlighted item is exposed through aria-activedescendant, the result count is announced politely, shortcuts are shown in kbd and declared on the trigger with aria-keyshortcuts. Escape closes and returns focus to the trigger.

    Without JavaScript

    The dialog stays closed and its trigger stays hidden; the links it contains must also exist in the page navigation, which is how the fixture is written.

    Common mistakes

    • Actions that exist only in the palette: keyboard-only discovery is not enough.
    • Using it for content search: that is what the site search is for; the palette is for actions and destinations.
    • Remembering recent items on shared devices without telling the reader.

    Class index

    Parts and modifiers of this family that the examples above do not show. The full list per stylesheet lives in the reference.

    ClassWhat it does
    iv-command__statusLive region that announces how many commands match.
    iv-command__item--activeItem under the virtual cursor; it follows aria-activedescendant, not focus.