cmdk for React: Build a Fast, Accessible Command Menu (⌘K)





cmdk React: Command Menu (⌘K), Install & Examples


cmdk for React: Build a Fast, Accessible Command Menu (⌘K)

A concise, practical guide to installing, wiring, and customizing cmdk in React—covering setup, keyboard handling (⌘K / Ctrl+K), accessibility, and a production-ready example.

Quick links: cmdk React · building command menus with cmdk in React

What is cmdk and why use it?

cmdk is a lightweight, React-first command menu / command palette library designed to create fast, searchable command interfaces like the macOS Spotlight or VSCode’s Command Palette. It gives you composable components for search input, lists, items, groups, and separators without enforcing presentation—ideal for teams that want keyboard-centric UX with minimal bundle cost.

Compared to prebuilt palettes, cmdk focuses on predictable keyboard navigation, fast filtering, and low friction composition. You control rendering, styling, and state, while cmdk supplies the accessible primitives and keyboard behavior. That makes it a great fit for apps that need a unified, extensible command center wired to actions and routes.

Use cases include global navigation (open pages), quick actions (create/toggle features), and developer utilities inside admin panels or editors. If you want to ship a responsive, searchable menu invoked by ⌘K (macOS) or Ctrl+K (Windows/Linux) with predictable focus and screen-reader semantics, cmdk is a high-quality choice.

Installation and initial setup

Install cmdk via npm or yarn. It’s small, so you can add it to a project without heavy dependencies. Example installs:

npm install cmdk
# or
yarn add cmdk

After installation, import the composables you need. At minimum you’ll use the Command root and a few child elements such as Command.Input, Command.List, and Command.Item. Styling is up to you—cmdk provides structure and behavior, not a visual theme.

Because cmdk is unopinionated visually, pair it with your CSS, Tailwind, or styled-components theme. If you want a modal-like behavior, render the Command root inside a dialog or overlay component. For quick starts, a simple absolute-positioned container works fine for dashboards and editing interfaces.

Core concepts and API

cmdk components form a predictable tree: Command (root) → Command.Input (search input) → Command.List (container) → Command.Item (actions). There are also Command.Group, Command.Separator, and Command.Empty. Each element is aware of keyboard focus and list navigation, so arrow keys, Enter, and Escape work by default.

Filtering: cmdk supports internal filtering based on item text, but you can supply filtered items from your own search logic for remote data or higher control. Items accept arbitrary children, so you can render icons, descriptions, and hotkeys while keeping the internal matching behavior intact.

State control: you typically control the open/closed state externally for global palettes. Toggle the Command rendering based on state and use callbacks to perform actions. By combining cmdk with routing or command dispatch, you can map results to app behaviors like navigation, API calls, or toggling features.

Example: Minimal command menu in React

Below is a minimal, production-minded example that demonstrates installation, wiring, and a ⌘K/Ctrl+K opener. It keeps a live list of items and shows how to execute actions on selection. Paste this inside a functional component.

import React, {useEffect, useState} from 'react';
import * as Cmdk from 'cmdk'; // or: import { Command } from 'cmdk';

function CommandPalette() {
  const [open, setOpen] = useState(false);
  const items = [
    {id: 'home', label: 'Go to Home', action: () => (window.location.href = '/')},
    {id: 'new',  label: 'Create New Document', action: () => console.log('create')},
    {id: 'search', label: 'Search Settings', action: () => console.log('search')}
  ];

  useEffect(() => {
    function onKey(e){
      const mod = e.metaKey || e.ctrlKey;
      if (mod && e.key.toLowerCase() === 'k') {
        e.preventDefault();
        setOpen(v => !v);
      }
      if (e.key === 'Escape') setOpen(false);
    }
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  return open ? (
    <div role="dialog" aria-modal="true">
      <Cmdk.Command onSelect={cmd => cmd.action()}>
        <Cmdk.Command.Input placeholder="Type a command or search..." />
        <Cmdk.Command.List>
          {items.map(it =>
            <Cmdk.Command.Item key={it.id} value={it.id} onSelect={() => it.action()}>
              {it.label}
            </Cmdk.Command.Item>
          )}
        </Cmdk.Command.List>
      </Cmdk.Command>
    </div>
  ) : null;
}

This example relies on cmdk’s keyboard handling for navigation and selection. It demonstrates a recommended pattern: manage visibility externally and let the command components handle focus and arrow-key movement.

For production, wire the item actions to your route manager (React Router, Next.js router) or to a centralized command dispatcher. Also add a visually hidden close button and an accessible label for the dialog/container for screen readers.

Keyboard navigation, ⌘K trigger, and accessibility

Keyboard behavior is central to a command palette. Capture the global key combination (Meta/Ctrl + K) to toggle the palette. Use event.preventDefault() to avoid native browser find/shortcut conflicts. For accessibility, always provide aria-labels and treat the palette as a modal (aria-modal=”true”) when it overlays content.

cmdk already implements roving focus and arrow-key navigation among items. Ensure each item has a clear label and, if necessary, an aria-describedby that points to a description element. For nested groups or complex actions, include role attributes (role=”menuitem”) to clarify semantics to assistive tech.

Test with keyboard-only navigation and a screen reader. Confirm that focus traps into the palette while open and returns to the originating control after close. If you’re using a custom dialog wrapper, keep focus management consistent—libraries like Reach UI or Radix provide solid helpers if you prefer not to roll your own.

Advanced usage and patterns

Beyond simple lists, cmdk supports grouping, separators, and custom rendering for results. Implement fuzzy matching (Fuse.js) for better search quality with large data sets. You can offload filtering to a web worker or remote API when the item set is big or dynamic.

Command macros: map items to command objects that contain metadata (category, hotkey, analytics-id). When selected, dispatch unified actions so analytics, undo stacks, and routing all receive the same command events. This keeps your command palette extensible and testable.

Performance: virtualize long lists with react-window or similar to avoid rendering thousands of DOM nodes. Provide a “recent commands” group and cache frequent queries. Finally, instrument the palette with analytics to measure helpfulness and discoverability of actions—this will inform which commands to promote.

Optimization for search engines and voice queries

For documentation and blog posts about cmdk, craft short, direct definitions near the top (this helps featured snippets). Use Q&A style headings (How to install cmdk in React?) to target People Also Ask boxes. Include code examples early, and keep JSON-LD FAQ markup for high-CTR snippet opportunities.

Voice search optimization benefits from conversational Q&A and short answers (under 40–50 words). Write at least one concise sentence per common question that could directly answer a voice query such as “How do I open the command menu?” or “What is the cmdk library for React?”.

To target featured snippets, present step-by-step installation and a one-line summary of the toggle shortcut. Use semantic HTML (h2/h3) and mark up examples with <pre> so crawlers detect code blocks and instant answers.

Semantic core (primary, secondary, clarifying)

This grouped semantic core is ready to use for on-page SEO—clusters include intent-focused queries, LSI keywords, and related phrases to integrate naturally into headings, captions, and code comments.

Primary (high intent) Secondary (how-to / product) Clarifying / LSI
cmdk cmdk React React command palette
React command menu cmdk installation React ⌘K menu
React command palette library cmdk setup cmdk tutorial
cmdk command menu cmdk example React keyboard navigation
cmdk getting started React searchable menu cmdk advanced usage
command palette React implement ⌘K in React accessible command palette

Short checklist before shipping

Two quick checks you should always make before launching a cmdk-powered feature:

  • Keyboard & accessibility: ensure focus management, aria labels, and Escape/closure behaviors are correct.
  • Performance & analytics: virtualize long lists and instrument item selection for discoverability metrics.

Implement tests for keyboard flows and include E2E coverage for the ⌘K toggle and top-level command actions. If you rely on remote suggestions, add debounce and server-side caching to minimize latency.

Finally, document public commands for your teammates—expose a small help overlay or a “?” command that lists common shortcuts and actions. It helps adoption and reduces support questions.

Related resources and backlinks

Official library and docs: cmdk React (GitHub). For a step-by-step tutorial and visuals, see this guide: building command menus with cmdk in React.

For more patterns and deeper accessibility notes, review React’s accessibility docs and consider integrating UI primitives like Radix or Reach for dialogs and overlays.

FAQ

Below are three high-value user questions with concise answers designed for quick consumption and voice-search friendliness.

How do I install and set up cmdk in React?

Install with npm install cmdk or yarn add cmdk, import the root and child components (Command, Command.Input, Command.List, Command.Item) and manage the open state externally. Add a global key listener for ⌘K/Ctrl+K to toggle the palette and wire item selection to routing or action dispatchers.

How do I trigger the command palette with ⌘K and support keyboard navigation?

Listen for a global keydown and check e.metaKey || e.ctrlKey together with e.key === 'k'. Prevent default, toggle palette visibility, and let cmdk handle arrow-key and Enter navigation. Ensure Escape closes the palette and focus returns to the source element on close.

Can I customize cmdk and is it accessible?

Yes. cmdk is unopinionated visually—apply your styles and custom rendering for items. It includes keyboard navigation primitives; you still need to apply aria labels, role attributes, and modal focus management to meet accessibility requirements. Test with keyboard-only workflows and a screen reader.

Published guide: cmdk command palette for React — concise, practical, and ready to integrate.