Component

Command Menu

IDE-style command palette with keyboard shortcuts, search filtering, grouped commands, and keyboard navigation hints.

  • Component
  • Tailwind
  • HTML
  • MIT

Preview

Live component

Interactive preview
Open preview
9:41 100%
devsnips.dev/library/tailwind/components/dropdowns/command-menu/
fluid · no fixed width 100%
No dependencies Production-ready

Install

Add to your project

terminal
npx devsnips add Tailwind/Components/Dropdowns/command-menu
registry path: Tailwind/Components/Dropdowns/command-menu

Source

Implementation

code.html
<!-- Command Menu (IDE-style) -->
<div class="relative">
  <div
    id="command-trigger"
    class="flex items-center gap-3 w-full max-w-lg px-4 py-3 bg-gray-100 border border-gray-200 rounded-xl cursor-pointer hover:bg-gray-200 transition-colors"
    onclick="openCommandMenu()"
  >
    <svg class="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
    </svg>
    <span class="flex-1 text-sm text-gray-500">Search commands, settings, or actions...</span>
    <kbd class="hidden sm:inline-flex items-center gap-1 px-2 py-1 text-xs text-gray-400 bg-white border border-gray-200 rounded">
      <span>⌘</span><span>K</span>
    </kbd>
  </div>

  <!-- Command Palette -->
  <div
    id="command-menu"
    class="hidden fixed inset-0 z-50 bg-black/50 flex items-start justify-center pt-24"
    onclick="closeCommandMenu(event)"
  >
    <div
      class="w-full max-w-xl bg-white rounded-2xl shadow-2xl border border-gray-200 overflow-hidden"
      onclick="event.stopPropagation()"
    >
      <!-- Search Input -->
      <div class="p-4 border-b border-gray-100">
        <div class="relative">
          <svg class="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
          </svg>
          <input
            type="text"
            id="command-search"
            class="w-full pl-12 pr-4 py-3 text-lg bg-gray-50 border-0 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
            placeholder="Type a command or search..."
            oninput="filterCommands(this.value)"
            autofocus
          />
        </div>
      </div>

      <!-- Command Categories -->
      <div class="max-h-96 overflow-y-auto">
        <!-- Navigation -->
        <div class="px-4 py-2">
          <p class="text-xs font-semibold text-gray-400 uppercase tracking-wider">Navigation</p>
        </div>
        <div class="px-2 pb-2">
          <button class="command-item w-full flex items-center gap-3 px-3 py-2.5 text-sm text-gray-700 rounded-lg hover:bg-blue-50 transition-colors" onclick="executeCommand('dashboard')">
            <svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path>
            </svg>
            <span>Go to Dashboard</span>
            <span class="ml-auto text-xs text-gray-400">⌘D</span>
          </button>
          <button class="command-item w-full flex items-center gap-3 px-3 py-2.5 text-sm text-gray-700 rounded-lg hover:bg-blue-50 transition-colors" onclick="executeCommand('projects')">
            <svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path>
            </svg>
            <span>Go to Projects</span>
            <span class="ml-auto text-xs text-gray-400">⌘P</span>
          </button>
          <button class="command-item w-full flex items-center gap-3 px-3 py-2.5 text-sm text-gray-700 rounded-lg hover:bg-blue-50 transition-colors" onclick="executeCommand('settings')">
            <svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
            </svg>
            <span>Open Settings</span>
            <span class="ml-auto text-xs text-gray-400">⌘,</span>
          </button>
        </div>

        <!-- Actions -->
        <div class="px-4 py-2 border-t border-gray-100">
          <p class="text-xs font-semibold text-gray-400 uppercase tracking-wider">Actions</p>
        </div>
        <div class="px-2 pb-2">
          <button class="command-item w-full flex items-center gap-3 px-3 py-2.5 text-sm text-gray-700 rounded-lg hover:bg-blue-50 transition-colors" onclick="executeCommand('new-file')">
            <svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
            </svg>
            <span>Create New File</span>
            <span class="ml-auto text-xs text-gray-400">⌘N</span>
          </button>
          <button class="command-item w-full flex items-center gap-3 px-3 py-2.5 text-sm text-gray-700 rounded-lg hover:bg-blue-50 transition-colors" onclick="executeCommand('share')">
            <svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"></path>
            </svg>
            <span>Share Project</span>
            <span class="ml-auto text-xs text-gray-400">⌘⇧S</span>
          </button>
          <button class="command-item w-full flex items-center gap-3 px-3 py-2.5 text-sm text-gray-700 rounded-lg hover:bg-blue-50 transition-colors" onclick="executeCommand('export')">
            <svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"></path>
            </svg>
            <span>Export as PNG</span>
            <span class="ml-auto text-xs text-gray-400">⌘E</span>
          </button>
        </div>

        <!-- Theme -->
        <div class="px-4 py-2 border-t border-gray-100">
          <p class="text-xs font-semibold text-gray-400 uppercase tracking-wider">Theme</p>
        </div>
        <div class="px-2 pb-4">
          <button class="command-item w-full flex items-center gap-3 px-3 py-2.5 text-sm text-gray-700 rounded-lg hover:bg-blue-50 transition-colors" onclick="executeCommand('theme')">
            <svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>
            </svg>
            <span>Toggle Dark Mode</span>
            <span class="ml-auto text-xs text-gray-400">⌘⇧D</span>
          </button>
        </div>
      </div>

      <!-- Footer -->
      <div class="px-4 py-3 bg-gray-50 border-t border-gray-100 flex items-center justify-between text-xs text-gray-500">
        <div class="flex items-center gap-4">
          <span class="flex items-center gap-1"><kbd class="px-1.5 py-0.5 bg-white border border-gray-200 rounded">↑↓</kbd> Navigate</span>
          <span class="flex items-center gap-1"><kbd class="px-1.5 py-0.5 bg-white border border-gray-200 rounded">↵</kbd> Select</span>
        </div>
        <span class="flex items-center gap-1"><kbd class="px-1.5 py-0.5 bg-white border border-gray-200 rounded">Esc</kbd> Close</span>
      </div>
    </div>
  </div>
</div>

<script>
  function openCommandMenu() {
    document.getElementById('command-menu').classList.remove('hidden');
    document.getElementById('command-search').focus();
  }

  function closeCommandMenu(event) {
    if (event.target.id === 'command-menu') {
      document.getElementById('command-menu').classList.add('hidden');
    }
  }

  function filterCommands(query) {
    const normalizedQuery = query.toLowerCase();
    document.querySelectorAll('.command-item').forEach(item => {
      const text = item.textContent.toLowerCase();
      if (text.includes(normalizedQuery)) {
        item.classList.remove('hidden');
      } else {
        item.classList.add('hidden');
      }
    });
  }

  function executeCommand(command) {
    console.log('Executing command:', command);
    document.getElementById('command-menu').classList.add('hidden');
  }

  document.addEventListener('keydown', function(event) {
    if ((event.metaKey || event.ctrlKey) && event.key === 'k') {
      event.preventDefault();
      openCommandMenu();
    }
    if (event.key === 'Escape') {
      document.getElementById('command-menu').classList.add('hidden');
    }
  });
</script>
168 lines UTF-8 · LF · Spaces: 2

AI-ready

Available to your agent.

This component is reachable through the DevSnips CLI, MCP server and Skills integrations — one registry, one resource path.

Resource path

devsnips://components/dropdowns/command-menu

Continue browsing

View all