{
  "title": "Command",
  "description": "cmdk-style command palette — search-filtered list inside a modal, with global ⌘K shortcut on web.",
  "url": "/docs/components/command",
  "since": "1.8.0",
  "tags": [
    "overlay",
    "search",
    "navigation"
  ],
  "platform": "both",
  "source": "---\ntitle: Command\ndescription: cmdk-style command palette — search-filtered list inside a modal, with global ⌘K shortcut on web.\nsince: 1.8.0\ntags: [overlay, search, navigation]\nplatform: both\ncategory: overlays\n---\n\nimport { BundleSize } from '@/components/bundle-size';\nimport { Preview } from '@/components/preview';\nimport { PropsTable } from '@/components/props-table';\n\n<BundleSize component=\"Command\" />\n\n## At a glance\n\n- Compound API: `Command`, `Command.Trigger`, `Command.Dialog`, `Command.Empty`, `Command.Group`, `Command.Item`, `Command.Shortcut`.\n- Web: global `⌘K` / `Ctrl+K` shortcut opens the palette. Search is a substring match (case-insensitive). Escape closes.\n- Native: trigger tap opens the modal; no global keyboard shortcut (React Native has no global key listener).\n- Reuses the `Dialog` primitive for the modal surface — inherits focus trap, scroll lock, backdrop blur, and Escape-to-close.\n\n## Preview\n\n<Preview name=\"command-basic\" />\n\n## Anatomy\n\n| Subcomponent | Role |\n|---|---|\n| `Command` | Root — owns open state and the filter query. Registers `⌘K`/`Ctrl+K` on web. |\n| `Command.Trigger` | Element that opens the palette when clicked/pressed. |\n| `Command.Dialog` | The modal surface — contains the search input and item list. |\n| `Command.Empty` | Shown automatically when the current query matches nothing. |\n| `Command.Group` | Labelled section of items. Hidden when all its items are filtered out. |\n| `Command.Item` | Selectable entry. Filtered by its text content against the current query. |\n| `Command.Shortcut` | Keyboard shortcut hint rendered right-aligned inside an Item. |\n\n## Full example\n\n```tsx\nimport { Command, Button, Kbd } from '@nori-ui/core';\n\n<Command>\n  <Command.Trigger>\n    <Button>\n      Search <Kbd>⌘K</Kbd>\n    </Button>\n  </Command.Trigger>\n  <Command.Dialog placeholder=\"Type a command or search…\">\n    <Command.Empty>No results found.</Command.Empty>\n    <Command.Group heading=\"Suggestions\">\n      <Command.Item onSelect={() => navigate('/calendar')}>Calendar</Command.Item>\n      <Command.Item onSelect={() => navigate('/emoji')}>Search Emoji</Command.Item>\n    </Command.Group>\n    <Command.Group heading=\"Settings\">\n      <Command.Item onSelect={() => navigate('/profile')}>\n        Profile\n        <Command.Shortcut>⌘P</Command.Shortcut>\n      </Command.Item>\n      <Command.Item onSelect={() => navigate('/billing')}>\n        Billing\n        <Command.Shortcut>⌘B</Command.Shortcut>\n      </Command.Item>\n    </Command.Group>\n  </Command.Dialog>\n</Command>\n```\n\n## Open state\n\n`open` (controlled) + `onOpenChange` for parent-driven state; `defaultOpen` for uncontrolled mode.\n\n```tsx\n// Uncontrolled — Trigger manages state.\n<Command>\n  <Command.Trigger><Button>Search</Button></Command.Trigger>\n  <Command.Dialog>...</Command.Dialog>\n</Command>\n\n// Controlled.\nconst [open, setOpen] = useState(false);\n<Command open={open} onOpenChange={setOpen}>\n  <Command.Trigger><Button>Search</Button></Command.Trigger>\n  <Command.Dialog>...</Command.Dialog>\n</Command>\n```\n\n## Global keyboard shortcut (web only)\n\nThe `Command` root registers a `keydown` listener for `⌘K` (macOS) / `Ctrl+K` (Windows/Linux) on `window`. This shortcut toggles the palette open/closed — no extra wiring needed.\n\nOn native, there is no global key listener. Use the `Command.Trigger` to open the palette.\n\n## Filtering\n\nItems are filtered by their **text content** using a case-insensitive substring match. The query is reset when the palette closes so the next open starts fresh.\n\n```tsx\n// \"calc\" matches \"Calculator\" and \"Calculate tax\"\n// but NOT \"Calendar\"\n<Command.Item onSelect={...}>Calculator</Command.Item>\n<Command.Item onSelect={...}>Calendar</Command.Item>  // hidden when query is \"calc\"\n```\n\nAn empty query shows everything.\n\n## Empty state\n\n`Command.Empty` renders when the query produces zero matching items across all groups. Place it directly inside `Command.Dialog` — the wrapper handles visibility automatically.\n\n```tsx\n<Command.Dialog>\n  <Command.Empty>No results found.</Command.Empty>\n  <Command.Group heading=\"Actions\">\n    <Command.Item onSelect={...}>Calendar</Command.Item>\n  </Command.Group>\n</Command.Dialog>\n```\n\n## Shortcuts\n\n`Command.Shortcut` renders right-aligned text inside a `Command.Item`:\n\n```tsx\n<Command.Item onSelect={openProfile}>\n  Profile\n  <Command.Shortcut>⌘P</Command.Shortcut>\n</Command.Item>\n```\n\n## Disabled items\n\n```tsx\n<Command.Item disabled onSelect={...}>Unavailable feature</Command.Item>\n```\n\nDisabled items still match the filter but do not fire `onSelect` when clicked.\n\n## Props\n\n### Command\n\n<PropsTable component=\"Command\" />\n\n### Command.Dialog\n\nThe modal surface that contains the search input and the item list. Accepts:\n\n- `children` — `Command.Empty`, `Command.Group`, and `Command.Item` nodes.\n- `placeholder` — text shown inside the search `<input>`. Defaults to `\"Type a command or search…\"`.\n- `className` — for custom width / padding overrides.\n\n### Command.Item\n\nA single selectable row inside a `Command.Group`. Accepts:\n\n- `children` — row content. Can include text and a `Command.Shortcut`.\n- `onSelect` — callback fired when the item is clicked or activated via Enter.\n- `disabled` — renders the item as non-interactive (still shown; filtered matches still apply).\n\n## v2 / deferred\n\n- **Fuzzy search** — v1 uses simple substring matching; fuzzy ranking (like fuse.js or cmdk's built-in) is a v2 follow-up.\n- **Async / remote items** — v1 works with static children only; async loading with a loading state is deferred.\n- **Customizable shortcut** — v1 hardcodes `⌘K`/`Ctrl+K`; a `shortcut` prop on `Command` is planned for v2.\n- **Keyboard navigation** — Arrow-Up/Down between items, Enter to select. v1 relies on standard DOM focus management via tab order; explicit arrow-key navigation is a v2 polish item.\n"
}
