Command

Command menu for search and quick actions.

About

shadcn/ui's Command component is built on cmdk. Basecoat implements the same command-menu pattern with vanilla HTML, CSS, and a small JavaScript controller for filtering, active item navigation, and dialog closing.

Usage

HTML + JavaScript

Step 1: Include the JavaScript files

You can either include the JavaScript file for all the components, or just the one for this component by adding this to the <head> of your page:

<script src="https://cdn.jsdelivr.net/npm/basecoat-css@1.0.0/dist/js/basecoat.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@1.0.0/dist/js/command.min.js" defer></script>

Step 2: Add your command HTML

<div id="demo-command-standalone" class="command border" aria-label="Command menu">
  <header>
    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-search-icon lucide-search">
      <circle cx="11" cy="11" r="8" />
      <path d="m21 21-4.3-4.3" />
    </svg>
    <input type="text" id="demo-command-standalone-input" placeholder="Type a command or search..." autocomplete="off" autocorrect="off" spellcheck="false" aria-autocomplete="list" role="combobox" aria-expanded="true" aria-controls="demo-command-standalone-menu" />
  </header>
  <div role="menu" id="demo-command-standalone-menu" aria-orientation="vertical" data-empty="No results found." class="scrollbar">
    <div role="group" aria-labelledby="suggestions">
      <span role="heading" id="suggestions">Suggestions</span>
      <div role="menuitem" data-filter="Calendar" data-keywords="date event schedule">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M8 2v4" />
          <path d="M16 2v4" />
          <rect width="18" height="18" x="3" y="4" rx="2" />
          <path d="M3 10h18" />
        </svg>
        <span>Calendar</span>
      </div>
      <div role="menuitem" data-filter="Search Emoji" data-keywords="emoji smile reaction">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <circle cx="12" cy="12" r="10" />
          <path d="M8 14s1.5 2 4 2 4-2 4-2" />
          <line x1="9" x2="9.01" y1="9" y2="9" />
          <line x1="15" x2="15.01" y1="9" y2="9" />
        </svg>
        <span>Search Emoji</span>
      </div>
      <div role="menuitem" aria-disabled="true">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <rect width="16" height="20" x="4" y="2" rx="2" />
          <line x1="8" x2="16" y1="6" y2="6" />
          <line x1="16" x2="16" y1="14" y2="18" />
          <path d="M16 10h.01" />
          <path d="M12 10h.01" />
          <path d="M8 10h.01" />
          <path d="M12 14h.01" />
          <path d="M8 14h.01" />
          <path d="M12 18h.01" />
          <path d="M8 18h.01" />
        </svg>
        <span>Calculator</span>
      </div>
    </div>
    <hr role="separator" />
    <div role="group" aria-labelledby="settings">
      <span role="heading" id="settings">Settings</span>
      <div role="menuitem" data-filter="Profile" data-keywords="user account">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" />
          <circle cx="12" cy="7" r="4" />
        </svg>
        <span>Profile</span>
      </div>
      <div role="menuitem" data-filter="Billing" data-keywords="invoice payment">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <rect width="20" height="14" x="2" y="5" rx="2" />
          <line x1="2" x2="22" y1="10" y2="10" />
        </svg>
        <span>Billing</span>
      </div>
      <div role="menuitem" data-filter="Settings" data-keywords="config preferences">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" />
          <circle cx="12" cy="12" r="3" />
        </svg>
        <span>Settings</span>
      </div>
    </div>
  </div>
</div>

Use <dialog class="command-dialog"> for the command palette variant.

<button class="btn-outline" onclick="document.getElementById('command-palette').showModal()">Open</button>
<dialog id="command-palette" class="command-dialog" aria-label="Command menu">
  <div class="command">
    <!-- Command content -->
  </div>
</dialog>

HTML structure

The command menu can be used standalone or inside a native dialog. The structure is:

<dialog class="command-dialog"> Optional
Dialog variant. Wraps one <div class="command">. Add aria-label or aria-labelledby for an accessible name.
<div class="command">
Root command menu. Can also be used standalone without the dialog wrapper.
<header>
Search input wrapper. The macro includes a search icon and input.
<input type="text" role="combobox">
Filter input. Use aria-expanded="true" and aria-controls="{ MENU_ID }" to point to the command list.
<div role="menu" id="{ MENU_ID }">
Command list. Set data-empty to customize the empty state.
<div role="group" aria-labelledby="{ HEADING_ID }"> Optional
Groups related command items. Hidden automatically when every item in the group is filtered out.
<span role="heading" id="{ HEADING_ID }"> Optional
Group heading. Use an id when the parent group uses aria-labelledby.
<div role="menuitem"> or <a role="menuitem">
Selectable command item. Use <a> for navigation and <div> for actions. Supports data-filter, data-keywords, data-force, data-keep-command-open, and aria-disabled="true".
<span data-shortcut> Optional
Shortcut hint aligned to the inline end of the item.
<span data-indicator> Optional
Item indicator. It becomes visible with data-checked="true" or aria-selected="true".
<hr role="separator"> Optional
Separator between groups/items. Hidden while filtering.

JavaScript API

basecoat:initialized
Once the component is initialized, it dispatches a custom non-bubbling basecoat:initialized event on itself.
command.refresh()
Rescans command items after changing children inside the existing role="menu" list.
window.basecoat.refresh(command)
Calls the component refresh method through the global dispatcher.

Jinja and Nunjucks

You can use the command() or command_dialog() Nunjucks or Jinja macros for this component.

{% call command() %}
  <div role="menuitem" data-keywords="date event">
    <svg>...</svg>
    <span>Calendar</span>
  </div>
  <div role="menuitem" data-keywords="config preferences">
    <svg>...</svg>
    <span>Settings</span>
  </div>
{% endcall %}

Examples

Basic

A simple command menu in a dialog. The button also shows the keyboard shortcut used in this example.

Shortcuts

Groups

Scrollable

RTL

Command supports document direction. Set dir="rtl" on the command root or a parent element.

API Reference

.command
Root command menu.
.command-dialog
Native dialog variant. Closes automatically when an item is clicked unless that item has data-keep-command-open.
data-filter
Overrides item text used by the filter.
data-keywords
Additional whitespace- or comma-separated search terms.
data-force
Always keeps an item visible while filtering.
data-empty
Custom empty-state text on the menu element.