Getting Started
Get cmdk-engine running in your React project in under 5 minutes.
Installation
npm install cmdk-engine cmdk react react-domOr with other package managers:
bun add cmdk-engine cmdk
pnpm add cmdk-engine cmdk
yarn add cmdk-engine cmdkPrefer Base UI? Install @base-ui/react instead of cmdk and import the palette from cmdk-engine/adapters/base-ui. See Adapters.
Requirements
- React 18 or 19.
- A UI adapter:
cmdk^1 for the cmdk adapter, or@base-ui/react^1.1 for the Base UI adapter. Or build your own UI with the hooks. - Optional:
react-router6, 7 or 8 for the route scanner, andmatch-sorter7 or 8 for the match-sorter search backend. - Node.js 20 or later, needed by the CLI only. The library runs in the browser and during SSR.
Support: the latest minor release gets fixes. While the version is 0.x, a minor release can change behavior; each such change is listed as a "Behavior change" in the changelog.
1. Add the Provider
Wrap your app with CommandEngineProvider, for example in a Providers component rendered once near the root. It initializes the command registry, search engine, and frecency tracker. Define config once, outside the component: a new object on every render rebuilds the engine.
import { CommandEngineProvider } from 'cmdk-engine/react'
const config = {
synonyms: {
billing: ['money', 'payment', 'credits'],
},
// Runs for commands with an href and no action. With a React Router
// data router, use (href) => router.navigate(href) to skip the reload.
onNavigate: (href: string) => window.location.assign(href),
frecency: { showRecent: true },
}
export function Providers({ children }: { children: React.ReactNode }) {
return <CommandEngineProvider config={config}>{children}</CommandEngineProvider>
}2. Register Commands
Use useCommandRegister to register commands from any component under the provider. Commands are removed when the component unmounts, so register app-wide navigation in a layout that stays mounted, and page-specific commands in the page.
import { useCommandRegister } from 'cmdk-engine/react'
import { CreditCard } from 'lucide-react'
function BillingPage() {
useCommandRegister([{
id: 'billing-overview',
label: 'Billing Overview',
href: '/billing/overview',
keywords: ['balance', 'credits'],
group: 'Billing',
icon: <CreditCard size={16} />,
}])
return <div>...</div>
}3. Add the Command Palette
Use the pre-wired cmdk adapter or build your own UI with hooks.
import { CommandPalette } from 'cmdk-engine/adapters/cmdk'
function CommandMenu() {
return <CommandPalette dialog placeholder="Search commands..." />
}4. Add Keyboard Shortcut
Call useCommandPaletteShortcut in a component inside the provider, such as the CommandMenu from step 3. Calling it in the component that renders the provider throws, because that component sits outside it.
import { CommandPalette, useCommandPaletteShortcut } from 'cmdk-engine/adapters/cmdk'
function CommandMenu() {
useCommandPaletteShortcut('k') // Cmd+K / Ctrl+K
return <CommandPalette dialog placeholder="Search commands..." />
}5. Style the Palette
CommandPalette ships no styles, so it looks unstyled until you add some. Copy the starter stylesheet (plain CSS or Tailwind) from the Styling page, then press Cmd+K (Ctrl+K on Windows and Linux).
Troubleshooting
... must be used within a <CommandEngineProvider>
A cmdk-engine hook or component ran outside the provider. The message starts with the name of the hook that failed, such as useCommandRegister, and lists the usual causes:
- The hook is called in the component that renders
CommandEngineProvider. Move it into a child component. - Two copies of
cmdk-engineare installed (in a monorepo, or at mismatched versions), so the component and the provider use different contexts. Make sure one copy resolves. - A bundler or test alias maps
cmdk-engine/reactor an adapter path but notcmdk-engine. The entries import each other by package name, so map them all.
The dialog never opens
A palette with dialog opens only when something toggles it. Call useCommandPaletteShortcut() in a component inside the provider, or call toggle() from useCommandPalette().
Next.js: "Event handlers cannot be passed to Client Component props"
Put 'use client' at the top of the file that renders the provider. A Server Component cannot pass functions such as onNavigate to it.
Next Steps
- Read the API Reference for all exports
- Pick an adapter, or switch to Base UI, on the Adapters page
- Use shadcn/ui or Next.js? Follow the shadcn/ui or Next.js guide
- See Examples for common patterns and runnable apps
- Explore the source code on GitHub