Table of Contents

Ctrl+K / ⌘K Spotlight Command Palette & Quick-Action Launcher Source Code

One of the most underrated UI components on the modern web is the Keyboard-First Command Palette (Ctrl+K or ⌘K). Popularized by developer tools like Linear, Vercel, Raycast, and GitHub, a command palette lets visitors search tutorials, jump to page sections, copy URLs, or trigger site actions (like switching themes or printing an article to PDF) in milliseconds without touching their mouse.

While most developers assume you need heavy React libraries like cmdk to build one, you can create a fast, accessible, zero-dependency Command Palette in pure HTML, CSS, and vanilla JavaScript.

Create a project folder with three files: index.html, style.css, and script.js.

1. HTML (index.html)

<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Ctrl+K Command Palette & Quick Action Launcher</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>

  <!-- Top Navigation Bar with Command Trigger -->
  <header class="navbar">
    <div class="logo">NitroX Web</div>

    <button id="openPaletteBtn" class="search-trigger-btn" type="button" aria-label="Open Command Palette">
      <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <circle cx="11" cy="11" r="8"></circle>
        <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
      </svg>
      <span class="trigger-placeholder">Quick search or run command...</span>
      <kbd id="osShortcutBadge" class="kbd-badge">Ctrl K</kbd>
    </button>
  </header>

  <!-- Demo Page Content -->
  <main class="demo-container">
    <span class="pill-badge">Underrated Power-User UX</span>
    <h1>Spotlight Command Palette (`Ctrl + K`)</h1>
    <p>Press <kbd id="heroShortcut">Ctrl + K</kbd> on your keyboard or click the search bar in the header above. Use the <kbd>↑</kbd> <kbd>↓</kbd> arrow keys to navigate, <kbd>Enter</kbd> to execute an action, and <kbd>Esc</kbd> to close.</p>

    <div class="feature-cards">
      <div class="f-card">
        <h3>Instant Live Filtering</h3>
        <p>Searches across site pages, tutorials, and interactive utility actions with highlighted keyword matches.</p>
      </div>
      <div class="f-card">
        <h3>100% Keyboard Driven</h3>
        <p>Built with roving highlight index management so power users never have to lift their hands from the keyboard.</p>
      </div>
      <div class="f-card">
        <h3>Action Execution</h3>
        <p>Does more than just open links—triggers dark/light mode, copies the page URL, or exports the guide to PDF.</p>
      </div>
    </div>
  </main>

  <!-- Command Palette Modal Backdrop -->
  <div id="paletteBackdrop" class="palette-backdrop" role="dialog" aria-modal="true" aria-labelledby="paletteSearchInput" hidden>
    <div class="palette-modal">
      
      <!-- Search Input Header -->
      <div class="palette-search-bar">
        <svg class="search-icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <circle cx="11" cy="11" r="8"></circle>
          <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
        </svg>
        <input 
          type="text" 
          id="paletteSearchInput" 
          class="palette-input" 
          placeholder="Type a command or search tutorials..." 
          autocomplete="off" 
          spellcheck="false"
        >
        <button id="closePaletteBtn" class="esc-btn" type="button" title="Close (Escape)">Esc</button>
      </div>

      <!-- Dynamic Results List -->
      <div id="paletteResults" class="palette-results" role="listbox">
        <!-- Populated dynamically via script.js -->
      </div>

      <!-- Modal Footer with Keyboard Hints -->
      <div class="palette-footer">
        <div class="footer-hints">
          <span><kbd>↑</kbd><kbd>↓</kbd> to navigate</span>
          <span><kbd>↵</kbd> to select</span>
          <span><kbd>Esc</kbd> to dismiss</span>
        </div>
        <span class="footer-brand">NitroX Command Engine</span>
      </div>

    </div>
  </div>

  <!-- Toast Notification for Quick Actions -->
  <div id="actionToast" class="action-toast" role="status" aria-live="polite" hidden></div>

  <script src="script.js"></script>
</body>
</html>

2. CSS (style.css)

/* ==========================================================================
   CSS Variables (Dark & Light Theme Support)
   ========================================================================== */
:root[data-theme="dark"] {
  --bg-page: #070a12;
  --bg-card: #101626;
  --bg-modal: #111827;
  --bg-input: #0b0f19;
  --border-color: #1e293b;
  --text-main: #f8fafc;
  --text-muted: #94a3b8;
  --accent-mint: #10b981;
  --accent-blue: #3b82f6;
  --item-hover: rgba(16, 185, 129, 0.12);
  --backdrop-bg: rgba(3, 6, 12, 0.75);
  --shadow-modal: 0 25px 50px -12px rgba(0, 0, 0, 0.75);
}

:root[data-theme="light"] {
  --bg-page: #f8fafc;
  --bg-card: #ffffff;
  --bg-modal: #ffffff;
  --bg-input: #f1f5f9;
  --border-color: #e2e8f0;
  --text-main: #0f172a;
  --text-muted: #64748b;
  --accent-mint: #059669;
  --accent-blue: #2563eb;
  --item-hover: rgba(5, 150, 105, 0.1);
  --backdrop-bg: rgba(15, 23, 42, 0.5);
  --shadow-modal: 0 25px 50px -12px rgba(15, 23, 42, 0.25);
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background-color: var(--bg-page);
  color: var(--text-main);
  line-height: 1.6;
  min-height: 100vh;
  transition: background-color 0.25s ease, color 0.25s ease;
}

/* ==========================================================================
   Header & Search Trigger Button
   ========================================================================== */
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 2rem;
  border-bottom: 1px solid var(--border-color);
  background-color: var(--bg-card);
}

.logo {
  font-weight: 800;
  font-size: 1.25rem;
  letter-spacing: -0.02em;
  color: var(--accent-mint);
}

.search-trigger-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  background-color: var(--bg-input);
  color: var(--text-muted);
  border: 1.5px solid var(--border-color);
  border-radius: 10px;
  padding: 0.5rem 0.85rem;
  font-size: 0.88rem;
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease;
}

.search-trigger-btn:hover {
  border-color: var(--accent-mint);
  color: var(--text-main);
}

.kbd-badge,
kbd {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.75rem;
  font-weight: 700;
  background-color: var(--bg-card);
  color: var(--text-main);
  border: 1px solid var(--border-color);
  border-bottom-width: 2px;
  border-radius: 5px;
  padding: 0.15rem 0.45rem;
}

/* ==========================================================================
   Demo Page Layout
   ========================================================================== */
.demo-container {
  max-width: 860px;
  margin: 4.5rem auto;
  padding: 0 1.5rem;
  text-align: center;
}

.pill-badge {
  display: inline-block;
  background: rgba(16, 185, 129, 0.12);
  color: var(--accent-mint);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.3rem 0.85rem;
  border-radius: 999px;
  margin-bottom: 1rem;
}

.demo-container h1 {
  font-size: 2.35rem;
  font-weight: 850;
  letter-spacing: -0.03em;
  margin-bottom: 0.85rem;
}

.demo-container > p {
  color: var(--text-muted);
  font-size: 1.05rem;
  max-width: 620px;
  margin: 0 auto 3rem;
}

.feature-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1.25rem;
  text-align: left;
}

.f-card {
  background-color: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: 14px;
  padding: 1.5rem;
}

.f-card h3 {
  font-size: 1rem;
  font-weight: 700;
  margin-bottom: 0.4rem;
}

.f-card p {
  font-size: 0.88rem;
  color: var(--text-muted);
}

/* ==========================================================================
   Command Palette Modal & Backdrop
   ========================================================================== */
.palette-backdrop {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background-color: var(--backdrop-bg);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 10vh 1rem 2rem;
  animation: fadeIn 0.15s ease-out;
}

.palette-backdrop[hidden] {
  display: none !important;
}

.palette-modal {
  width: 100%;
  max-width: 620px;
  background-color: var(--bg-modal);
  border: 1px solid var(--border-color);
  border-radius: 16px;
  box-shadow: var(--shadow-modal);
  overflow: hidden;
  animation: slideDown 0.18s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slideDown {
  from { opacity: 0; transform: scale(0.96) translateY(-10px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}

/* Search Input Bar */
.palette-search-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border-color);
}

.search-icon {
  color: var(--accent-mint);
  flex-shrink: 0;
}

.palette-input {
  width: 100%;
  background: transparent;
  border: none;
  color: var(--text-main);
  font-size: 1.05rem;
  font-family: inherit;
  outline: none;
}

.palette-input::placeholder {
  color: var(--text-muted);
}

.esc-btn {
  background-color: var(--bg-input);
  color: var(--text-muted);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  padding: 0.25rem 0.55rem;
  font-size: 0.75rem;
  font-weight: 700;
  cursor: pointer;
}

.esc-btn:hover {
  color: var(--text-main);
}

/* Results List & Groups */
.palette-results {
  max-height: 360px;
  overflow-y: auto;
  padding: 0.65rem;
}

.palette-group-title {
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  padding: 0.5rem 0.75rem 0.35rem;
}

.palette-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem 0.85rem;
  border-radius: 10px;
  cursor: pointer;
  transition: background-color 0.12s ease;
}

.palette-item.active,
.palette-item:hover {
  background-color: var(--item-hover);
}

.item-left {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 0;
}

.item-icon {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  background-color: var(--bg-input);
  border: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
  color: var(--accent-mint);
  flex-shrink: 0;
}

.item-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.item-title {
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--text-main);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.item-title mark {
  background: transparent;
  color: var(--accent-mint);
  font-weight: 800;
  text-decoration: underline;
}

.item-subtitle {
  font-size: 0.78rem;
  color: var(--text-muted);
}

.item-badge {
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--text-muted);
  background-color: var(--bg-input);
  border: 1px solid var(--border-color);
  padding: 0.2rem 0.55rem;
  border-radius: 6px;
  flex-shrink: 0;
}

.empty-results {
  text-align: center;
  padding: 2.5rem 1rem;
  color: var(--text-muted);
  font-size: 0.92rem;
}

/* Modal Footer */
.palette-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.65rem 1.25rem;
  background-color: var(--bg-input);
  border-top: 1px solid var(--border-color);
  font-size: 0.75rem;
  color: var(--text-muted);
}

.footer-hints {
  display: flex;
  gap: 1rem;
}

.footer-brand {
  font-weight: 700;
  color: var(--accent-mint);
}

/* Toast Notification */
.action-toast {
  position: fixed;
  bottom: 1.75rem;
  right: 1.75rem;
  background-color: var(--accent-mint);
  color: #05080e;
  font-weight: 700;
  font-size: 0.88rem;
  padding: 0.75rem 1.25rem;
  border-radius: 10px;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.35);
  z-index: 10000;
}

@media (max-width: 600px) {
  .trigger-placeholder {
    display: none;
  }
  .footer-brand {
    display: none;
  }
}

3. JavaScript (script.js)

document.addEventListener('DOMContentLoaded', () => {
  const openPaletteBtn = document.getElementById('openPaletteBtn');
  const closePaletteBtn = document.getElementById('closePaletteBtn');
  const paletteBackdrop = document.getElementById('paletteBackdrop');
  const paletteSearchInput = document.getElementById('paletteSearchInput');
  const paletteResults = document.getElementById('paletteResults');
  const osShortcutBadge = document.getElementById('osShortcutBadge');
  const heroShortcut = document.getElementById('heroShortcut');
  const actionToast = document.getElementById('actionToast');

  // 1. Detect Mac vs Windows/Linux for accurate shortcut badge
  const isMac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
  if (isMac) {
    osShortcutBadge.textContent = '⌘ K';
    heroShortcut.textContent = '⌘ + K';
  }

  // 2. Toast Notification Helper
  let toastTimeout;
  const showToast = (message) => {
    clearTimeout(toastTimeout);
    actionToast.textContent = message;
    actionToast.hidden = false;
    toastTimeout = setTimeout(() => {
      actionToast.hidden = true;
    }, 2400);
  };

  // 3. Command Registry (Pages, Tutorials & Live Site Actions)
  const COMMAND_ITEMS = [
    {
      id: 'act-theme',
      category: 'Quick Actions',
      title: 'Toggle Dark / Light Theme',
      subtitle: 'Switch the website color scheme immediately',
      icon: '◐',
      badge: 'Action',
      keywords: 'dark mode light mode theme color switch',
      action: () => {
        const html = document.documentElement;
        const next = html.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
        html.setAttribute('data-theme', next);
        showToast(`Switched to ${next.toUpperCase()} theme`);
      }
    },
    {
      id: 'act-copy-url',
      category: 'Quick Actions',
      title: 'Copy Current Page URL',
      subtitle: 'Copy a shareable link to your clipboard',
      icon: '🔗',
      badge: 'Clipboard',
      keywords: 'copy link url share clipboard',
      action: async () => {
        await navigator.clipboard.writeText(window.location.href);
        showToast('Page URL copied to clipboard!');
      }
    },
    {
      id: 'act-print',
      category: 'Quick Actions',
      title: 'Save or Print Page as PDF',
      subtitle: 'Open clean print view for offline reading',
      icon: '🖨',
      badge: 'Utility',
      keywords: 'print pdf save download offline',
      action: () => {
        window.print();
      }
    },
    {
      id: 'tut-contact',
      category: 'Tutorials & Code Snippets',
      title: 'Responsive Contact Form in HTML, CSS & JS',
      subtitle: 'Includes validation, honeypot anti-spam, and PHP/API action setup',
      icon: '</>',
      badge: 'Tutorial',
      keywords: 'contact form email validation php ajax fetch',
      url: '#contact-form-tutorial'
    },
    {
      id: 'tut-stego',
      category: 'Tutorials & Code Snippets',
      title: 'Image Steganography & Bit-Plane Forensics Studio',
      subtitle: 'Hide AES-256 encrypted secrets inside PNG pixels',
      icon: '🛡',
      badge: 'Project',
      keywords: 'steganography encryption aes canvas security lsb',
      url: '#steganography-studio'
    },
    {
      id: 'tut-toc',
      category: 'Tutorials & Code Snippets',
      title: 'Auto Table of Contents with Scroll-Spy',
      subtitle: 'IntersectionObserver TOC + reading progress bar',
      icon: '📑',
      badge: 'Component',
      keywords: 'table of contents toc scrollspy headings progress',
      url: '#auto-toc-guide'
    },
    {
      id: 'nav-home',
      category: 'Navigation',
      title: 'Go to Homepage',
      subtitle: 'Return to the main NitroX Web dashboard',
      icon: '🏠',
      badge: 'Page',
      keywords: 'home index main start',
      url: '#home'
    }
  ];

  let filteredItems = [...COMMAND_ITEMS];
  let activeIndex = 0;

  // 4. Highlight Matching Characters Safely
  const highlightMatch = (text, query) => {
    if (!query) return text;
    const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    const regex = new RegExp(`(${escaped})`, 'gi');
    return text.replace(regex, '<mark>$1</mark>');
  };

  // 5. Render Filtered Command List
  const renderResults = (query = '') => {
    const cleanQuery = query.trim().toLowerCase();

    filteredItems = COMMAND_ITEMS.filter((item) => {
      if (!cleanQuery) return true;
      const haystack = `${item.title} ${item.subtitle} ${item.category} ${item.keywords}`.toLowerCase();
      // Multi-word token matching (every typed word must appear somewhere in the haystack)
      return cleanQuery.split(/\s+/).every((token) => haystack.includes(token));
    });

    activeIndex = 0;
    paletteResults.innerHTML = '';

    if (filteredItems.length === 0) {
      paletteResults.innerHTML = `<div class="empty-results">No matching commands or tutorials found for "<strong>${cleanQuery}</strong>".</div>`;
      return;
    }

    // Group items by category while preserving flat index for keyboard navigation
    const categories = [...new Set(filteredItems.map((i) => i.category))];
    let flatIndex = 0;

    categories.forEach((category) => {
      const groupTitle = document.createElement('div');
      groupTitle.className = 'palette-group-title';
      groupTitle.textContent = category;
      paletteResults.appendChild(groupTitle);

      filteredItems
        .filter((item) => item.category === category)
        .forEach((item) => {
          const currentIndex = flatIndex++;
          const itemEl = document.createElement('div');
          itemEl.className = `palette-item ${currentIndex === activeIndex ? 'active' : ''}`;
          itemEl.setAttribute('role', 'option');
          itemEl.dataset.index = currentIndex;

          itemEl.innerHTML = `
            <div class="item-left">
              <div class="item-icon">${item.icon}</div>
              <div class="item-text">
                <span class="item-title">${highlightMatch(item.title, cleanQuery)}</span>
                <span class="item-subtitle">${item.subtitle}</span>
              </div>
            </div>
            <span class="item-badge">${item.badge}</span>
          `;

          itemEl.addEventListener('mouseenter', () => {
            setActiveItem(currentIndex, false);
          });

          itemEl.addEventListener('click', () => {
            executeItem(item);
          });

          paletteResults.appendChild(itemEl);
        });
    });
  };

  // 6. Update Active Highlighted Item
  const setActiveItem = (newIndex, scrollIntoView = true) => {
    const items = paletteResults.querySelectorAll('.palette-item');
    if (!items.length) return;

    activeIndex = (newIndex + items.length) % items.length;

    items.forEach((el, idx) => {
      const isSelected = idx === activeIndex;
      el.classList.toggle('active', isSelected);
      if (isSelected && scrollIntoView) {
        el.scrollIntoView({ block: 'nearest' });
      }
    });
  };

  // 7. Execute Selected Command or Navigate to URL
  const executeItem = (item) => {
    if (!item) return;
    closePalette();

    if (typeof item.action === 'function') {
      item.action();
    } else if (item.url) {
      window.location.hash = item.url;
      showToast(`Navigated to ${item.title}`);
    }
  };

  // 8. Open & Close Modal Controls
  const openPalette = () => {
    paletteBackdrop.hidden = false;
    paletteSearchInput.value = '';
    renderResults('');
    document.body.style.overflow = 'hidden';
    setTimeout(() => paletteSearchInput.focus(), 10);
  };

  const closePalette = () => {
    paletteBackdrop.hidden = true;
    document.body.style.overflow = '';
  };

  openPaletteBtn.addEventListener('click', openPalette);
  closePaletteBtn.addEventListener('click', closePalette);

  paletteBackdrop.addEventListener('click', (e) => {
    if (e.target === paletteBackdrop) closePalette();
  });

  paletteSearchInput.addEventListener('input', (e) => {
    renderResults(e.target.value);
  });

  // 9. Global Keyboard Shortcuts (Ctrl+K / Cmd+K, Arrows, Enter, Escape)
  document.addEventListener('keydown', (e) => {
    // Toggle on Ctrl+K or Cmd+K
    if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k') {
      e.preventDefault();
      if (paletteBackdrop.hidden) {
        openPalette();
      } else {
        closePalette();
      }
      return;
    }

    // Only process navigation keys when palette is open
    if (paletteBackdrop.hidden) return;

    if (e.key === 'Escape') {
      e.preventDefault();
      closePalette();
    } else if (e.key === 'ArrowDown') {
      e.preventDefault();
      setActiveItem(activeIndex + 1);
    } else if (e.key === 'ArrowUp') {
      e.preventDefault();
      setActiveItem(activeIndex - 1);
    } else if (e.key === 'Enter') {
      e.preventDefault();
      if (filteredItems[activeIndex]) {
        executeItem(filteredItems[activeIndex]);
      }
    }
  });
});

How to Build a Ctrl+K / ⌘K Spotlight Command Palette in HTML, CSS & Vanilla JavaScript

If you use modern developer platforms like GitHub, Vercel, Linear, Stripe Docs, or Tailwind CSS, you have likely noticed a subtle search bar in the header displaying a Ctrl K or ⌘ K keyboard shortcut badge. Pressing that shortcut opens a centered Command Palette—an instant, keyboard-driven launcher that lets you search documentation, jump between pages, copy links, or toggle dark mode without ever reaching for your mouse.

Despite being one of the highest-converting UX upgrades you can add to a technical blog, documentation site, or developer portfolio, most websites still don’t have one because developers assume it requires a complex React setup. In this guide, we will break down how our dependency-free HTML, CSS, and Vanilla JS Command Palette works under the hood and how you can wire it up to index your own site content automatically.

1. Intercepting Ctrl+K and ⌘K Without Breaking Browser Defaults

In Windows and Linux browsers, pressing Ctrl + K historically focused the browser’s built-in address bar. To override that default behavior cleanly and support macOS users pressing Command (⌘) + K, we listen for keydown at the document level and check both e.ctrlKey and e.metaKey:

document.addEventListener('keydown', (e) => {
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k') {
    e.preventDefault(); // Stops browser address bar focus
    paletteBackdrop.hidden ? openPalette() : closePalette();
  }
});

To make the UI feel native on every operating system, our initialization script inspects navigator.platform on page load and automatically swaps the <kbd> badge text from Ctrl K to ⌘ K for Mac, iPhone, and iPad visitors.

2. Multi-Token Search Filtering & Live Match Highlighting

Simple .includes() search filters break down as soon as a user types two words that aren’t right next to each other. For example, if an article is titled “Responsive Contact Form in HTML, CSS & JS” and a visitor types "contact js", a strict substring check returns zero results because "contact js" does not appear as a contiguous phrase.

Our filter solves this using Multi-Token Array Matching:

const haystack = `${item.title} ${item.subtitle} ${item.category} ${item.keywords}`.toLowerCase();
return cleanQuery.split(/\s+/).every((token) => haystack.includes(token));

By splitting the user’s search query on whitespace (\s+) and verifying that .every() word token exists somewhere in the combined title, subtitle, category, or keyword string, visitors can type keywords in any order and immediately find the right tutorial or command.

3. Roving Keyboard Index & Auto-Scrolling Listbox

For a Command Palette to feel instantaneous, users must be able to cycle from the top result to the bottom result using the ArrowDown and ArrowUp keys, wrapping around seamlessly at the ends.

We accomplish this with modular arithmetic ((newIndex + items.length) % items.length) paired with the native DOM scrollIntoView({ block: 'nearest' }) method:

activeIndex = (newIndex + items.length) % items.length;
if (isSelected && scrollIntoView) {
  el.scrollIntoView({ block: 'nearest' });
}

Passing { block: 'nearest' } ensures the scrollable results container only scrolls when the highlighted item moves outside the visible viewport window, preventing jarring jumps when navigating middle items.

4. Bonus: Automatically Indexing Page Headings & Links (Dynamic DOM Crawler)

Don’t want to maintain the COMMAND_ITEMS array manually on large pages or WordPress posts? You can append a 10-line DOM crawler right inside script.js that automatically scans every <h2> heading on the current article and adds it to the Command Palette under an "On This Page" group:

// Automatically add all H2 sections on the current page into the Command Palette
document.querySelectorAll('article h2, .entry-content h2').forEach((h2, idx) => {
  if (!h2.id) h2.id = `section-${idx + 1}`;
  COMMAND_ITEMS.push({
    id: `sec-${idx}`,
    category: 'On This Page',
    title: h2.textContent.trim(),
    subtitle: 'Jump directly to this article section',
    icon: '#',
    badge: 'Section',
    keywords: h2.textContent.toLowerCase(),
    url: `#${h2.id}`
  });
});

With those lines added, every single tutorial on your site automatically gains a searchable "Jump to Section" spotlight index alongside your global navigation links and quick actions!