Agent Skills: Command Palette Pattern

Build keyboard-driven command palettes using cmdk + shadcn/ui. Use when: (1) Adding command palette to web apps, (2) Implementing keyboard navigation, (3) Building spotlight-style search, (4) Setting up cmdk with shadcn components.

UncategorizedID: gwenwindflower/.charmschool/web-ux-command-palette

Install this agent skill to your local

pnpm dlx add-skill https://github.com/gwenwindflower/.charmschool/tree/HEAD/agents/shared/skills/web-ux-command-palette

Skill Files

Browse the full folder contents for web-ux-command-palette.

Download Skill

Loading file tree…

agents/shared/skills/web-ux-command-palette/SKILL.md

Skill Metadata

Name
web-ux-command-palette
Description
"Build keyboard-driven command palettes using cmdk + shadcn/ui. Use when: (1) Adding command palette to web apps, (2) Implementing keyboard navigation, (3) Building spotlight-style search, (4) Setting up cmdk with shadcn components."

Command Palette Pattern

Overview

Build performant, keyboard-first command palettes using cmdk (the industry standard) with shadcn/ui components.

Why cmdk + shadcn:

  • De facto standard (Vercel, Linear, Raycast-style UIs)
  • Built-in fuzzy search
  • Accessible (Radix Dialog primitives)
  • Keyboard-first design

Core Components

| Component | Purpose | | --- | --- | | CommandDialog | Modal wrapper (Dialog + Command) | | CommandInput | Search input with icon | | CommandList | Scrollable results container | | CommandEmpty | "No results" state | | CommandGroup | Categorized sections with headings | | CommandItem | Individual selectable items | | CommandSeparator | Visual divider between groups | | CommandShortcut | Keyboard shortcut hint display |

Basic Structure

<CommandDialog open={open} onOpenChange={setOpen}>
  <CommandInput placeholder="Type a command..." />
  <CommandList>
    <CommandEmpty>No results found.</CommandEmpty>
    <CommandGroup heading="Navigation">
      <CommandItem onSelect={() => navigate('/home')}>
        <HomeIcon /> Home
      </CommandItem>
    </CommandGroup>
  </CommandList>
</CommandDialog>

Keyboard Shortcuts

Standard bindings:

  • Cmd+K / Ctrl+K - Open/close (standard convention)
  • / - Open (when not in input field)
  • Escape - Close
  • Arrow keys - Navigate
  • Enter - Select

Implementation:

useEffect(() => {
  const handler = (e: KeyboardEvent) => {
    if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
      e.preventDefault();
      setOpen(prev => !prev);
    }
    if (e.key === '/' && !isInputFocused(e.target)) {
      e.preventDefault();
      setOpen(true);
    }
  };
  document.addEventListener('keydown', handler);
  return () => document.removeEventListener('keydown', handler);
}, []);

function isInputFocused(target: EventTarget | null): boolean {
  return target instanceof HTMLElement &&
    ['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName);
}

Search Index Patterns

Static sites:

  • Build index at compile time
  • Pass as props to component

Dynamic:

  • Fetch on mount or use server action

Structure:

interface SearchItem {
  title: string;
  description?: string;
  href: string;
  type: string;  // e.g., "page", "blog", "command"
  keywords?: string[];
}

cmdk search:

  • Searches the value prop on CommandItem
  • Include searchable text in value: value={title + ' ' + keywords?.join(' ')}

Styling Customization

Height:

<CommandList className="max-h-[300px]">

Dialog position:

  • Centered by default via DialogContent

Item states:

<CommandItem className="data-[selected=true]:bg-accent">

Accessibility

Built-in:

  • Focus trap (Radix Dialog)
  • Escape/click-outside handling
  • Arrow navigation (cmdk)
  • Screen reader announcements

Ensure:

  • Visible focus indicators
  • Meaningful item labels
  • Icon-only items have aria-label

External Resources

Command Palette Pattern Skill | Agent Skills