Command Palette
Keyboard-first command dialog built on cmdk: grouped items, fuzzy search, optional `href` navigation, and `onItemSelect` for custom actions.
Default
Open from a button; wire ⌘K in your layout. Rows with `href` navigate; others use `onItemSelect`.
Bind ⌘K in your app root (this site already uses it for the global header search).
Example palette
Try fuzzy search and keyboard navigation
default-example.tsx
1"use client";23import { useState } from "react";4import { CommandPalette } from "@/registry/ui";5import type { CommandPaletteGroup } from "@/registry/ui";6import { Button } from "@/components/ui/button";78const demoGroups: CommandPaletteGroup[] = [9 {10 heading: "Navigate",11 items: [12 {13 id: "docs",14 label: "Documentation",15 subtitle: "Getting started",16 href: "/docs",17 keywords: "help guide",18 },19 {20 id: "components",21 label: "Components",22 subtitle: "Browse library",23 href: "/components",24 },25 {26 id: "blocks",27 label: "Blocks",28 subtitle: "Higher-level UI",29 href: "/blocks",30 },31 ],32 },33 {34 heading: "Actions",35 items: [36 {37 id: "palette-self",38 label: "Command palette",39 subtitle: "This component",40 href: "/components/command-palette",41 keywords: "cmdk search",42 },43 {44 id: "log",45 label: "Log selection",46 subtitle: "No href - uses callback",47 keywords: "demo console",48 },49 ],50 },51];5253export function CommandPaletteDefaultExample() {54 const [open, setOpen] = useState(false);55 const [lastAction, setLastAction] = useState<string | null>(null);5657 return (58 <div className="space-y-4">59 <div className="flex flex-wrap items-center gap-2">60 <Button type="button" onClick={() => setOpen(true)}>61 Open command palette62 </Button>63 <span className="text-xs text-muted-foreground">64 Bind <kbd className="rounded border bg-muted px-1 font-mono">⌘K</kbd>{" "}65 in your app root (this site already uses it for the global header66 search).67 </span>68 </div>69 {lastAction ? (70 <p className="text-sm text-muted-foreground">71 Last callback selection:{" "}72 <span className="font-mono text-foreground">{lastAction}</span>73 </p>74 ) : null}75 <CommandPalette76 open={open}77 onOpenChange={setOpen}78 groups={demoGroups}79 groupOrder={["Navigate", "Actions"]}80 title="Example palette"81 description="Try fuzzy search and keyboard navigation"82 placeholder="Search pages and actions…"83 onItemSelect={(item) => {84 if (item.id === "log") {85 setLastAction(item.label);86 }87 }}88 />89 </div>90 );91}
Installation & source
Install via the shadcn CLI or copy the registry files manually.
bash
npx shadcn@latest add @tt-ui/command-palette
Props
| Name | Type | Default | Description |
|---|---|---|---|
| open / onOpenChange | boolean / (open: boolean) => void | - | Controlled dialog visibility |
| groups | CommandPaletteGroup[] | [] | Each group has `heading` and `items` (id, label, optional subtitle, keywords, href, disabled) |
| groupOrder | string[] | order of first occurrence in groups | Headings to render and their order |
| title / description | string | accessibility labels for the dialog | DialogTitle / DialogDescription (visually hidden by default) |
| placeholder / emptyMessage | string | Type a command… / No results found. | Command input placeholder and empty state text |
| onItemSelect | (item: CommandPaletteItem) => void | undefined | Invoked when a row has no `href` (navigation uses `router.push` when `href` is set) |