Command Palette — Free HTML CSS JS Cmd+K Snippet

Command Palette · Modals · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Cmd+K and Ctrl+K shortcut opens the palette via document keydown listener
Substring filter on name and description — searches both fields simultaneously
Grouped results by group field with group label headers
Arrow key navigation: ArrowDown/Up calls setActive() + scrollIntoView
Enter runs the active command; ESC closes the palette
backdrop-filter blur overlay with scale+opacity open animation
data-idx attributes allow onclick delegation to individual items
Export as HTML file, React JSX, or React + Tailwind CSS
Mobile (375px), Tablet (768px), Desktop device preview buttons
Live split-pane editor — preview updates as you type

About this UI Snippet

Command Palette — Cmd+K Shortcut, Grouped Commands, Fuzzy Search & Keyboard Nav

Screenshot of the Command Palette snippet rendered live

A command palette is a searchable list of application actions triggered by a keyboard shortcut — typically Cmd+K or Ctrl+K. Popularised by VS Code and Linear, it is now a standard power-user feature in developer tools, dashboards, and productivity apps. It replaces deep menu hierarchies with a single search interface: type a few characters and instantly find any action.

The COMMANDS data structure

Commands are plain JS objects with group, icon, name, desc, and shortcut fields. The render(cmds) function groups them by the group field and renders each group with a label and its items. Adding new commands is as simple as adding an object to the array.

The search/filter function

filter(q) converts the query to lowercase and calls COMMANDS.filter(c => c.name.toLowerCase().includes(lq) || c.desc.toLowerCase().includes(lq)). This searches both name and description — typing "dashboard" finds commands named "Open Dashboard" and commands with "dashboard" in their description. Passing the result to render() re-builds the list.

Keyboard navigation

A keydown listener on the input catches ArrowDown, ArrowUp, Enter, and Escape. Arrow keys call setActive(i) which removes .active from all items, adds it to the target item, and calls scrollIntoView({ block: 'nearest' }) so the active item is always visible. Enter calls pick(activeIdx) to execute the command. Escape calls closePalette().

Opening and closing

document.addEventListener('keydown', e => { if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); openPalette(); } }) wires the Cmd+K shortcut. openPalette() adds .show to the overlay and palette and focuses the search input with a 50ms delay (allowing the CSS transition to start first). closePalette() removes .show from both.

Replacing alert() with real actions

The pick(i) function currently calls alert(). Replace it with a switch statement or a map from command name to handler function to execute real actions.

Keyboard shortcut capture

The Cmd+K / Ctrl+K listener checks: if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); openPalette(); }. e.preventDefault() stops the browser's default Cmd+K action (some browsers map this to a bookmark or search action). The listener is attached to document once on component mount and remains active globally while the page is open.

The fuzzy search algorithm

The search filters commands by checking if the query string is a substring of the command name or description: cmd.name.toLowerCase().includes(q) || cmd.desc.toLowerCase().includes(q). For a true fuzzy match (allowing out-of-order character matching), replace includes with a character-order test: const chars = [...q]; let idx = 0; return name.split('').some(c => c === chars[idx] && ++idx) && idx === chars.length. This matches "cmpl" to "command palette".

Arrow key navigation

The keydown handler tracks selectedIndex state. ArrowDown increments it (wrapping at the list end); ArrowUp decrements (wrapping to the end). The selected command gets a highlighted background. Enter triggers the selected command's action and closes the palette. The selectedIndex is reset to 0 on each new search query.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to trace the keyboard handling and grouping logic line by line to trust it. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how setActive keeps the highlighted item in sync between the data-idx attribute, the visible array, and scrollIntoView, and why the Cmd+K listener needs to check both metaKey and ctrlKey rather than just one. The same assistant can help optimize it — for instance asking whether rebuilding the entire innerHTML string on every keystroke is fine at eleven commands but would need a different approach at a few hundred. It's also useful for extending the palette: ask it to add real fuzzy matching instead of plain substring search, support recently-used commands pinned to the top, or wire pick() to an actual router/action dispatcher instead of the placeholder alert. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a Cmd+K command palette in plain HTML, CSS, and JavaScript — no fuzzy-search library, no UI framework.

Requirements:
- A global keydown listener on document that detects both e.metaKey and e.ctrlKey combined with the "k" key, calls preventDefault to stop the browser's own shortcut, and opens the palette from anywhere on the page without requiring focus to be inside it first.
- A flat array of command objects, each with a group name, an icon, a name, a description, and an optional keyboard shortcut string, rendered by grouping commands under their group label headers dynamically (not hardcoded per-group markup).
- A search input that filters the command array by checking whether the lowercased query is a substring of either the command's name or its description, re-rendering the grouped list on every keystroke and resetting the active selection to the first result each time.
- Full keyboard navigation inside the open palette: ArrowDown and ArrowUp move a highlighted-item index up or down clamped to the list bounds, calling scrollIntoView with block: "nearest" so the highlighted item is always visible without page-level scrolling, Enter executes the highlighted command, and Escape closes the palette.
- An empty state shown when no commands match the current query.
- Open/close must be driven by toggling a class that animates opacity and a scale transform on the palette panel plus a separate blurred backdrop overlay, not by toggling display or visibility directly.
- Focus the search input automatically after opening, with enough delay that the open transition has already started.

Step by step

How to Use

  1. 1
    Press Cmd+K in the previewClick inside the preview and press Cmd+K (or Ctrl+K) to open the palette. Or click the "Open palette" button.
  2. 2
    Type to searchType any word to filter commands by name or description. The list filters in real time as you type.
  3. 3
    Navigate with arrow keys and EnterUse ArrowDown/ArrowUp to move between commands. Press Enter to run the selected command. Press ESC to close.
  4. 4
    Add your own commandsIn the JS panel, add objects to the COMMANDS array: { group: "My Group", icon: "⭐", name: "My Command", desc: "What it does", shortcut: "⌘X" }.
  5. 5
    Wire pick() to real actionsReplace the alert() in pick(i) with a switch on visible[i].name or a map of command names to handler functions.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.

Real-world uses

Common Use Cases

SaaS dashboard navigation
Replace deep navigation menus like the mega menu with a command palette. Users type instead of clicking through multiple levels to find an action.
Developer tool quick actions
Add to any developer tool for keyboard-first power users — pair with a keyboard shortcuts cheatsheet. Wire commands to real actions: navigate to files, run builds, toggle settings.
Learn keyboard event handling and DOM rendering
The palette uses keydown, metaKey/ctrlKey detection, and dynamic DOM rendering. Edit the JS to understand how each part works.
Prototype keyboard-first UX
Use the palette in a prototype to test whether a keyboard-centric navigation model works for your user base before building a full implementation.
Customise grouping and icons
Update the group field on COMMANDS to create your own sections. Change the icon field to SVG strings or emoji to match your visual style.
Accessibility-first navigation
The command palette makes deep features discoverable without hunting through menus — valuable for power users and keyboard-only users alike.

Got questions?

Frequently Asked Questions

A document.addEventListener("keydown") handler checks (e.metaKey || e.ctrlKey) && e.key === "k". metaKey is true on Mac for the Command key; ctrlKey is true on Windows/Linux for Control. e.preventDefault() stops the browser default Cmd+K action. Then openPalette() is called.

filter(q) converts the query to lowercase and filters COMMANDS where c.name.toLowerCase().includes(lq) or c.desc.toLowerCase().includes(lq). Both name and description are searched. The filtered array is passed to render() which rebuilds the grouped list.

The keydown handler on the input catches ArrowDown (increment activeIdx), ArrowUp (decrement), and Enter (execute). setActive(i) removes .active from all items, adds it to the item with data-idx={i}, and calls el.scrollIntoView({ block: "nearest" }) to keep the active item visible.

Replace the alert() in pick(i) with your action logic. Use a switch on visible[i].name, or create an actions map: const handlers = { "Go to Home": () => router.push("/"), ... }. Then pick calls handlers[visible[i].name]?.().

Add objects to the COMMANDS array in the JS panel: { group: "MyGroup", icon: "⭐", name: "My Action", desc: "Does something useful", shortcut: "" }. The render function groups and displays them automatically.

Yes. Click "JSX" for a React component. In React, manage open state with useState, filter state with useState, and active index with useState. Use useEffect to add/remove the document keydown listener. Wire the search input to a controlled value.