react ~5 KB 0 deps v0.3.0 β†— GitHub β†—

@mshafiqyajid/react-command-palette

⌘K command palette for React. Headless hook + styled component. Fuzzy match against label/hint/keywords, item grouping, recent-items section, full keyboard navigation, configurable global hotkey (⌘K / Ctrl+K). Zero dependencies, fully typed.

Playground #

Props
TSX
import { CommandPaletteStyled } from "@mshafiqyajid/react-command-palette/styled";
import "@mshafiqyajid/react-command-palette/styles.css";

<CommandPaletteStyled
  items={items}
  open={open}
  onOpenChange={setOpen}
  onSelect={(item) => /* … */}
  withRecent
  withFooter
/>

Install #

npm install @mshafiqyajid/react-command-palette

Quick start #

import { CommandPaletteStyled } from "@mshafiqyajid/react-command-palette/styled";
import "@mshafiqyajid/react-command-palette/styles.css";

const items = [
  { id: "new",      label: "New file",      group: "File", shortcut: "⌘N" },
  { id: "open",     label: "Open recent",   group: "File", keywords: ["history"] },
  { id: "find",     label: "Find in files", group: "Edit", shortcut: "⌘F" },
  { id: "settings", label: "Open settings", group: "App" },
];

<CommandPaletteStyled
  items={items}
  onSelect={(item) => console.log(item.id)}
  recentStorageKey="my-app-cmd-recent"
/>

Opens automatically on ⌘K / Ctrl+K. Up/Down moves, Enter selects, Esc closes.

Headless #

import { useCommandPalette } from "@mshafiqyajid/react-command-palette";

const cmd = useCommandPalette({ items, onSelect });

return cmd.isOpen ? (
  <div role="dialog">
    <input {...cmd.inputProps} placeholder="Type a command…" />
    <ul {...cmd.listProps}>
      {cmd.groups.map((g) => (
        <section key={g.id}>
          <h4>{g.label}</h4>
          {g.items.map((item) => (
            <li key={item.id} {...cmd.getItemProps(item)}>{item.label}</li>
          ))}
        </section>
      ))}
    </ul>
  </div>
) : null;

API #

PropTypeDefaultDescription
itemsCommandItem[]β€”Required. Items to render.
onSelect(item) => voidβ€”Fires on Enter / click
defaultOpen / open / onOpenChangebooleanfalseOpen state (uncontrolled or controlled)
defaultQuerystring""Initial search value
filter(item, q) => booleansubstring matchCustom filter (fuzzy/score)
recentStorageKeystringβ€”Persists last 5 selections via localStorage
hotkey{ key, meta?, ctrl?, shift? } | null{ key: "k", meta: true, ctrl: true }Global open shortcut
placeholderstring"Type a command…"Search input placeholder
emptyTextReactNode"No results."Shown when no items match
emptyState(query) => ReactNodeβ€”Custom empty state β€” receives the active query. Overrides emptyText.
loadingbooleanfalseShow a loading row instead of items (use with async filtering)
loadingTextReactNode"Loading…"Loading row text
highlightMatchesbooleantrueBolden matched query characters in labels
footerReactNodeβ€”Footer slot (keyboard hints, etc)

CommandItem #

FieldTypeDescription
idstringRequired, unique
labelstringRequired, matched by filter
hintstring?Secondary text + matched by filter
iconReactNode?Left-side icon
shortcutstring?Right-side keyboard hint
groupstring?Section heading
disabledboolean?Skipped by keyboard nav
keywordsstring[]?Extra search terms
dataT?Free-form payload
Edit this page on GitHub