Skip to content
DesignOSby h4rithd
Components/Command Palette
ui / overlay

Command Palette

A Spotlight-style command surface with Cmd/Ctrl K, filtering, and keyboard selection.

PREVIEW READY
LIVE PREVIEWDARK / LIGHT COMPATIBLE
INSTALL / SOURCE REGISTRY

Add Command Palette to your project

The command adds the component source and its DesignOS base dependency.

$pnpm dlx shadcn@latest add https://designos.h4rithd.com/r/command-palette.json
registry/default/ui/command-palette.tsx
"use client"

import * as React from "react"
import { Search } from "lucide-react"
import "@/components/designos/designos.css"

export type CommandItem = { id: string; label: string; group?: string; keywords?: string[]; icon?: React.ReactNode; shortcut?: string; onSelect: () => void }

export function CommandPalette({ items, placeholder = "Search commands…", open, onOpenChange }: { items: CommandItem[]; placeholder?: string; open?: boolean; onOpenChange?: (open: boolean) => void }) {
  const dialog = React.useRef<HTMLDialogElement>(null)
  const input = React.useRef<HTMLInputElement>(null)
  const [query, setQuery] = React.useState("")
  const [active, setActive] = React.useState(0)
  const visible = React.useMemo(() => { const needle = query.toLowerCase().trim(); return needle ? items.filter((item) => [item.label, item.group, ...(item.keywords ?? [])].join(" ").toLowerCase().includes(needle)) : items }, [items, query])
  React.useEffect(() => {
    const shortcut = (event: KeyboardEvent) => { if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") { event.preventDefault(); if (dialog.current?.open) dialog.current.close(); else dialog.current?.showModal() } }
    window.addEventListener("keydown", shortcut)
    return () => window.removeEventListener("keydown", shortcut)
  }, [])
  React.useEffect(() => { if (open === true && !dialog.current?.open) dialog.current?.showModal(); if (open === false && dialog.current?.open) dialog.current.close() }, [open])
  const choose = (item: CommandItem | undefined) => { if (!item) return; item.onSelect(); dialog.current?.close() }
  return <dialog ref={dialog} className="dos-command" aria-label="Command palette" onClose={() => { setQuery(""); setActive(0); onOpenChange?.(false) }} onCancel={() => onOpenChange?.(false)} onClick={(event) => { if (event.target === dialog.current) dialog.current.close() }}>
    <div className="dos-command__search"><Search aria-hidden="true" /><input ref={input} className="dos-command__input" value={query} onChange={(event) => { setQuery(event.target.value); setActive(0) }} placeholder={placeholder} aria-label={placeholder} autoFocus onKeyDown={(event) => { if (event.key === "ArrowDown") { event.preventDefault(); setActive((value) => Math.min(value + 1, visible.length - 1)) } if (event.key === "ArrowUp") { event.preventDefault(); setActive((value) => Math.max(value - 1, 0)) } if (event.key === "Enter") { event.preventDefault(); choose(visible[active]) } }} /><kbd className="dos-command__shortcut">ESC</kbd></div>
    <div role="listbox" aria-label="Results" className="dos-command__list">{visible.length === 0 ? <div className="dos-command__empty">No matching commands</div> : visible.map((item, index) => <button key={item.id} role="option" aria-selected={index === active} data-active={index === active} type="button" className="dos-command__item" onPointerMove={() => setActive(index)} onClick={() => choose(item)}>{item.icon}<span>{item.label}</span>{item.shortcut && <kbd className="dos-command__shortcut">{item.shortcut}</kbd>}</button>)}</div>
  </dialog>
}

Component contract

  • Source-owned after installation
  • Dark and light theme variables
  • Keyboard and visible-focus behavior
  • Reduced-motion fallback
  • Responsive from 320px upward
  • IBM Plex Sans + JetBrains Mono hierarchy