Command

Fast, composable command menu for quick navigation and actions.

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@0.3.3/dist/js/basecoat.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@0.3.3/dist/js/command.min.js" defer></script>

Step 2: Add your command HTML

You can use the command menu standalone:

<div id="demo-command-standalone" class="command rounded-lg border shadow-md" 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-value="calendar" onclick="console.log('Open calendar')">
        <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-value="search-emoji" onclick="console.log('Search emoji')">
        <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" data-value="calculator" 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-value="profile" onclick="console.log('Open profile')">
        <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>
        <kbd class="ml-auto text-muted-foreground bg-transparent tracking-widest">⌘P</kbd>
      </div>
      <div role="menuitem" data-value="billing" onclick="console.log('Open billing')">
        <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>
        <kbd class="ml-auto text-muted-foreground bg-transparent tracking-widest">⌘B</kbd>
      </div>
      <div role="menuitem" data-value="settings" onclick="console.log('Open settings')">
        <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>
        <kbd class="ml-auto text-muted-foreground bg-transparent tracking-widest">⌘S</kbd>
      </div>
    </div>
  </div>
</div>

Wrap the command menu in a <dialog class="command-dialog"> to display in a dialog:

<dialog class="command-dialog" aria-label="Command menu">
  <div class="command">
    <!-- Regular command content: header, menu, etc. -->
  </div>
</dialog>

HTML structure

<dialog class="command-dialog"> Optional
For dialog variant, wraps a <div class="command"> to display as a modal. Uses native <dialog> behavior and requires aria-label or aria-labelledby for accessibility.
<div class="command">
Wraps around the entire command component. Can be used standalone or inside a dialog.
<header>
Contains the search input to filter command options.
<input type="text">
The search input. Should have:
  • role="combobox": indicates the input controls a menu with filtering
  • aria-expanded="true": the menu is always expanded
  • aria-controls="{ MENU_ID }": points to the menu's id
<div role="menu">
The menu containing the command items. Should have id="{ MENU_ID }" refered to by the input's aria-controls attribute.
<div role="menuitem">
Command item that triggers an action when clicked. In a command-dialog, clicking a menuitem automatically closes the dialog unless the data-keep-command-open attribute is present. Optional attributes:
  • data-label: custom label for filtering (if different from text content)
  • data-keywords: additional keywords for enhanced filtering
  • aria-disabled="true": marks item as disabled (excluded from keyboard navigation and filtering)
<hr role="separator"> Optional
Separator between groups/items. Hidden when filtering is active.
<div role="group"> Optional
Group of items, can have aria-labelledby attribute to link to a heading.
<span role="heading">
Group heading, must have an id attribute if you use the aria-labelledby attribute on the group.

JavaScript events

basecoat:initialized
Once the component is fully initialized, it dispatches a custom (non-bubbling) basecoat:initialized event on itself.

Jinja and Nunjucks

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

{% call command() %}
  <div role="menuitem" data-value="calendar">
    <svg>...</svg>
    <span>Calendar</span>
  </div>
  <div role="menuitem" data-value="settings">
    <svg>...</svg>
    <span>Settings</span>
  </div>
{% endcall %}

Examples

Dialog

You can use some simple JavaScript to open the command menu with a keyboard shortcut (in this case ⌘J).