Navigation

Command Palette Dialog

The command palette in a modal, toggled with ⌘K / Ctrl+K. Full screen on phones.

Last chosen: nothing yet

Installation

Install the package (React 19):

terminal
npm install @krackedui/motion

Import the styles once, in your app entry or root layout:

/src/main.tsx
import '@krackedui/motion/styles.css';

Use it anywhere inside your app's <Theme> (see Installation):

/src/CommandPaletteDialogExample.tsx
import { useState } from 'react';
import { Button, CommandPaletteDialog, type CommandGroup } from '@krackedui/motion';

const groups: CommandGroup[] = [
  { label: 'Pages', items: [
    { id: 'roadmap', title: 'Product roadmap', icon: 'file', keywords: 'plan goals', path: ['Team', 'Projects'] },
    { id: 'notes', title: 'Weekly sync notes', icon: 'file', path: ['Team', 'Meetings'] },
    { id: 'guide', title: 'Onboarding guide', icon: '📘' },
  ] },
  { label: 'Actions', items: [
    { id: 'new', title: 'New page', icon: 'plus', shortcut: '⌘N' },
    { id: 'theme', title: 'Toggle dark mode', icon: 'moon', keywords: 'appearance theme', shortcut: '⌘⇧L' },
    { id: 'settings', title: 'Open settings', icon: 'settings', shortcut: '⌘,' },
  ] },
];

export function Search() {
  const [open, setOpen] = useState(false);
  const [picked, setPicked] = useState<string | null>(null);
  return (
    <div className="flex flex-col items-center gap-2">
      <Button variant="secondary" icon="search" onClick={() => setOpen(true)}>Search…</Button>
      <CommandPaletteDialog
        open={open}
        onOpenChange={setOpen}
        // ⌘K / Ctrl+K toggles it when hotkey is on (the default)
        hotkey={false}
        groups={groups}
        placeholder="Search pages and actions…"
        emptyText="No pages or actions match"
        onSelect={(item) => setPicked(item.id)}
      />
      <div role="status" className="text-[12px] text-n-text-secondary">Last chosen: {picked ?? 'nothing yet'}</div>
    </div>
  );
}

Examples

Search dialog

Last chosen: nothing yet

With preview pane

Wide screens show the highlighted item on the right.

Last chosen: nothing yet

API Reference

CommandPaletteDialog

Accepts every CommandPalette prop, plus:

PropTypeDefault
open
boolean
defaultOpen
boolean
false
onOpenChange
(open: boolean) => void
hotkey
boolean
true
width
number
640 (1006 with preview)
height
number
title
string
"Command palette"
groups
{ label: string; items: CommandItem[] }[]
onSelect
(item: CommandItem) => void
placeholder
string
"Search…"
inputLabel
string
emptyText
ReactNode
"No results"
filters
{ label: string; icon?: IconName; menu?: boolean; muted?: boolean; onClick?: () => void }[]
[]
hints
{ keys: ReactNode; label: string }[]
↑↓ Navigate, ↵ Select, esc Close
preview
boolean
false
defaultSelectedId
string
query
string
onQueryChange
(query: string) => void
autoFocus
boolean
false
headerEnd
ReactNode

Accessibility

  • A WAI-ARIA modal dialog (named "Command palette" by default) containing the combobox: focus goes to the search input on open and is trapped in the dialog.
  • ⌘K / Ctrl+K toggles it (when hotkey is on); Escape or a click outside closes it; focus returns to where it was.
  • The input is a WAI-ARIA combobox (aria-expanded, aria-controls, aria-autocomplete="list", aria-activedescendant) controlling an always-visible listbox; focus stays in the input.
  • Typing filters by title, keywords and path (every word must match). ↑/↓ move the highlight, Ctrl+Home / Ctrl+End jump to the ends, Enter runs the highlighted item.
  • Groups are labelled groups; options expose aria-selected for the highlighted one; disabled items are skipped.
  • When nothing matches, the empty text is announced through a status region.
  • Under 640px it fills the screen; the result list scrolls inside. Opens and closes with the shared motion layer (styles/motion.css); with prefers-reduced-motion: reduce it only fades.

Usage

  • Use as the app-wide search and command launcher, opened from a search button and ⌘K.
  • Selecting an item calls onSelect and closes the dialog: navigate or run the command there.
  • Turn hotkey off when another part of the page already owns ⌘K.
© 2026 Motion. Internal documentation.