| name | Command Palette Developer |
| description | This skill should be used when the user asks to "create a command palette", "build a command palette", "add command palette", "implement ⌘K search", "create search modal", "build keyboard navigation", "add command menu", "create Raycast-style interface", "build spotlight search", or mentions cmdk, command bar, command menu, or keyboard-first navigation. Provides comprehensive guidance for building professional command palettes with React, TypeScript, Tailwind, and modern tooling including cmdk, Floating UI, Zustand, Tanstack Query, and Tanstack Virtual. |
| version | 1.0.0 |
Command Palette Development
Build professional command palette interfaces for web applications using React, TypeScript, and Tailwind CSS. Command palettes provide keyboard-first navigation that enables power users to access functionality without leaving the keyboard, combining CLI efficiency with GUI discoverability.
Purpose & When to Use
Command palettes solve the tension between feature-rich applications and clean interfaces. Instead of cluttering screens with buttons and menus, palettes consolidate functionality into a searchable, keyboard-driven interface that appears on demand (typically via ⌘K or ⌘+Shift+P).
Use command palettes when building applications that:
- Have numerous actions or navigation targets (20+ commands)
- Serve power users who prefer keyboard workflows
- Need searchable, discoverable functionality
- Require context-aware command suggestions
- Want to provide multi-step command flows (e.g., select repository → choose action)
This skill provides generator scripts, templates, examples, and comprehensive guidance for implementing command palettes matching the quality of Raycast, Linear, GitHub, and Notion.
Choosing Implementation Patterns
Modal Palette - Centered overlay with backdrop (⌘K standard):
- Use for: App-wide actions, global search, navigation
- Examples: GitHub's command palette, VS Code's command palette
- Generated with:
create-command-palette.sh --type modal
Embedded Palette - Floating element attached to trigger:
- Use for: Contextual actions, inline search, form controls
- Examples: Notion's slash commands, mention autocomplete
- Generated with:
create-command-palette.sh --type embedded
Drawer Palette - Slide-in panel from screen edge:
- Use for: Filter panels, advanced search, settings navigation
- Examples: Raycast's Store, application settings
- Generated with:
create-command-palette.sh --type drawer
Quick Start Guide
1. Initial Setup
Install dependencies and create base configuration:
cd /path/to/your/project
/path/to/skills/command-palette-dev/scripts/setup-palette-stack.sh
This script:
- Detects your package manager (npm/pnpm/yarn/bun)
- Installs required packages:
cmdk, @floating-ui/react, zustand, @tanstack/react-query, @tanstack/react-virtual
- Creates
ThemeProvider.tsx and CommandProvider.tsx
- Sets up
command-registry.ts for command registration
- Adds Tailwind configuration for palette variants
- Validates existing dependencies and suggests remediation if issues found
2. Generate Your First Palette
Create a basic modal command palette:
./scripts/create-command-palette.sh \
--type modal \
--name SearchPalette \
--output ./src/components
This generates:
SearchPalette.tsx - Main component with keyboard navigation
SearchPalette.types.ts - TypeScript interfaces
index.ts - Barrel export
3. Integrate into Application
Wrap your app with providers:
import { ThemeProvider } from './providers/ThemeProvider';
import { CommandProvider } from './providers/CommandProvider';
import { SearchPalette } from './components/SearchPalette';
function App() {
return (
<ThemeProvider>
<CommandProvider>
<YourApp />
<SearchPalette />
</CommandProvider>
</ThemeProvider>
);
}
Register commands:
import { useCommandRegistry } from './providers/CommandProvider';
function MyComponent() {
const registry = useCommandRegistry();
useEffect(() => {
registry.register({
id: 'navigate-home',
label: 'Go to Dashboard',
keywords: ['home', 'dashboard', 'main'],
shortcut: 'g then d',
icon: HomeIcon,
onSelect: () => navigate('/'),
});
}, []);
}
4. Customize Layout and Results
Generate specific layout patterns:
./scripts/create-palette-layout.sh \
--layout two-column \
--name FileSearch \
--with-preview
./scripts/create-palette-layout.sh \
--layout card-grid \
--name StorePalette \
--virtualized
Create typed result components:
./scripts/create-result-type.sh \
--type person \
--name PersonResult
./scripts/create-result-type.sh \
--type file \
--name FileResult \
--with-actions
Core Concepts
Command Palette Anatomy
Every command palette consists of four essential parts:
- Trigger - Keyboard shortcut or button that opens the palette (⌘K, ⌘+Shift+P)
- Input Field - Search box with real-time fuzzy filtering
- Results List - Filtered commands with keyboard navigation (arrow keys, enter)
- Footer (optional) - Keyboard legend showing available shortcuts
The cmdk library handles filtering, keyboard navigation, and accessibility automatically. Focus on command registration and result rendering.
Layout Patterns
Command palettes support multiple layout configurations depending on data richness and use case:
Single-Column List - Basic vertical list of results:
- Best for: Simple actions, text-heavy commands, mobile
- Performance: Excellent (handles 2,000-3,000 items)
- Reference:
references/layouts.md for implementation details
Two-Column with Preview - List on left, detail panel on right:
- Best for: Files, documents, rich content needing preview
- Examples: Raycast file search, GitHub repository picker
- Requires: Preview component that updates on selection change
Multi-Panel - Sidebar filters + center results + right details:
- Best for: Complex filtering, data tables, admin panels
- Examples: AWS console command palette
- Consideration: Responsive behavior on smaller screens
Card Grid - Rich cards with images, badges, metadata:
- Best for: Extensions, plugins, visual content
- Examples: Raycast Store, Figma plugin browser
- Requires: Virtual scrolling for 100+ items
Horizontal Cards + Lists - Mixed layout with scrollable cards and list items:
- Best for: Grouped content types, contextual results
- Examples: Linear's command palette
- Implementation: Combine multiple result type components
For detailed layout implementations and responsive strategies, see references/layouts.md.
Result Types
Different command types require different visual presentations:
- Person - Avatar, name, email/role, status indicators
- File - File type icon, name, size, modification date
- Action - Action icon, label, description, keyboard shortcut
- Card - Image, title, description, badges, metadata
Generate result components with create-result-type.sh to get type-safe, accessible implementations matching your design system.
State Management with Zustand
Command palettes maintain several state concerns:
interface CommandPaletteState {
isOpen: boolean;
searchQuery: string;
selectedId: string | null;
recentCommands: Command[];
favorites: string[];
commandStack: Command[];
}
The generated CommandProvider uses Zustand for lightweight, performant state management. For server-side search, Tanstack Query handles caching and loading states separately.
Detailed state patterns and integration with Tanstack Query are documented in references/state-management.md.
Theming System
All generated palettes support three theme modes:
- Light - Light backgrounds, dark text
- Dark - Dark backgrounds, light text
- System - Follows OS preference via
prefers-color-scheme
Themes use CSS variables for runtime switching without re-renders:
:root {
--palette-bg: white;
--palette-text: black;
}
[data-theme="dark"] {
--palette-bg: #1a1a1a;
--palette-text: white;
}
Tailwind's dark mode integrates seamlessly. For custom theme creation and per-palette overrides, see references/theming.md.
Generator Scripts Guide
Five generator scripts create components without reading templates into context:
create-command-palette.sh
Generate complete palette components:
./scripts/create-command-palette.sh \
--type modal|embedded|drawer \
--name ComponentName \
--output ./src/components \
--theme light|dark|system
Flags:
--type (required) - Palette variant: modal, embedded, drawer
--name (required) - Component name in PascalCase
--output (default: ./src/components) - Output directory
--theme (default: system) - Theme mode
--with-footer (default: true) - Include keyboard legend
--with-groups (default: true) - Support command groups
--interactive - Prompt for all options
create-palette-layout.sh
Generate layout-specific components:
./scripts/create-palette-layout.sh \
--layout single-column|two-column|multi-panel|card-grid|horizontal-cards \
--name ComponentName \
--virtualized
Flags:
--layout (required) - Layout pattern
--name (required) - Component name
--output (default: ./src/components) - Output directory
--virtualized (default: false) - Enable Tanstack Virtual for 10k+ items
--with-preview (default: true for two-column) - Add preview panel
create-result-type.sh
Generate typed result components:
./scripts/create-result-type.sh \
--type person|file|action|card \
--name ResultComponent \
--with-actions
Flags:
--type (required) - Result type
--name (required) - Component name
--output (default: ./src/components/results) - Output directory
--with-avatar (default: true for person) - Include avatar
--with-icon (default: true) - Include icon
--with-metadata (default: true) - Include metadata line
--with-actions (default: false) - Include inline action buttons
setup-palette-stack.sh
Initial project setup:
./scripts/setup-palette-stack.sh \
--project-root . \
--with-examples
What it does:
- Detects package manager
- Validates Node/TypeScript versions
- Installs dependencies with version compatibility check
- Creates provider components
- Initializes command registry
- Configures Tailwind for palettes
- Optionally copies working examples
add-palette-feature.sh
Add features to existing palettes:
./scripts/add-palette-feature.sh \
--feature virtual-scroll|server-search|keyboard-shortcuts|recent-commands|favorites|multi-step \
--target ./src/SearchPalette.tsx
Features:
virtual-scroll - Tanstack Virtual for 10k+ items
server-search - Tanstack Query integration with debouncing
keyboard-shortcuts - ⌘+1-9 favorites and custom bindings
recent-commands - Track and display recent usage
favorites - Pin commands with persistence
multi-step - Nested command flows with breadcrumbs
Workflow Patterns
Basic palette creation:
setup-palette-stack.sh
create-command-palette.sh --type modal --name Actions
Rich file search:
create-palette-layout.sh --layout two-column --name FileSearch
create-result-type.sh --type file --name FileResult
add-palette-feature.sh --feature virtual-scroll --target FileSearch.tsx
API-driven search:
create-command-palette.sh --type modal --name ApiSearch
add-palette-feature.sh --feature server-search --target ApiSearch.tsx
Additional Resources
Reference Files
Comprehensive documentation in references/:
design-principles.md - UX patterns, fuzzy search, discovery, accessibility from research
layouts.md - Detailed implementation guides for all five layout patterns
theming.md - CSS variables, Tailwind integration, custom themes, reduced motion
keyboard-navigation.md - Arrow keys, shortcuts, focus traps, multi-key sequences
state-management.md - Zustand patterns, command registry, Tanstack Query integration
server-side-search.md - API integration, debouncing, pagination, infinite scroll
virtual-scrolling.md - Tanstack Virtual setup, performance benchmarks, dynamic heights
testing.md - Vitest + RTL unit tests, Playwright E2E, performance testing
floating-positioning.md - Floating UI middleware for embedded palettes
plugin-system.md - Extensibility patterns, third-party command providers
analytics.md - Telemetry patterns (reference only, not in examples)
Example Implementations
Working examples in examples/:
file-search/ - Virtual scroll, fuzzy search, file metadata, recent files
action-palette/ - Grouped actions, keyboard shortcuts, icons
navigation/ - Breadcrumbs, route groups, search history
multi-step/ - Nested commands, command chaining, back navigation (Raycast-style)
server-search/ - API integration, Tanstack Query, debounce, loading states
virtual-list/ - 10k+ items, Tanstack Virtual, performance optimizations
Each example includes a README explaining what it demonstrates and key implementation details.
Utility Functions
Reusable TypeScript utilities in utilities/:
fuzzy-search.ts - Fuzzy matching, scoring, highlight rendering
keyboard-shortcuts.ts - Shortcut parsing, matching, hooks, display formatting
command-registry.ts - Command registration API, searching, grouping, providers
theme-utils.ts - Theme detection, switching, CSS variable generation
Copy these files into your project and customize as needed.
Scripts Directory
All generator scripts with dependency validation:
create-command-palette.sh - Main palette generator
create-palette-layout.sh - Layout variants
create-result-type.sh - Result components
setup-palette-stack.sh - Initial project setup
add-palette-feature.sh - Feature additions
Scripts validate dependencies before generation and provide remediation steps for missing or incompatible packages.
Best Practices
Performance:
- Use virtual scrolling (Tanstack Virtual) for 1,000+ items
- Debounce server searches (300-500ms)
- Memoize result components to prevent re-renders
- Lazy load preview content
Accessibility:
- Maintain focus trap when palette is open
- Announce result count changes to screen readers
- Support keyboard-only navigation
- Respect
prefers-reduced-motion
User Experience:
- Show recent/frequent commands on open
- Provide empty state guidance for new users
- Display keyboard shortcuts next to commands
- Support fuzzy search for typo tolerance
Architecture:
- Keep command registration decentralized (register in feature components)
- Use Zustand for UI state, Tanstack Query for server state
- Separate result rendering from business logic
- Design for plugin extensibility from the start
For detailed guidance on each best practice, consult the relevant reference documentation.
Getting Help
Common Issues:
- Palette doesn't open - Check keyboard shortcut conflicts, verify trigger is registered
- Search not filtering - Ensure commands have
keywords array, check fuzzy search configuration
- Results not rendering - Verify result type components are imported, check TypeScript types
- Poor performance - Enable virtual scrolling, check for unnecessary re-renders with React DevTools
Deep Dives:
- Layout not working as expected →
references/layouts.md
- Theme not switching →
references/theming.md
- Keyboard nav issues →
references/keyboard-navigation.md
- Server search slow →
references/server-side-search.md
- Testing failures →
references/testing.md
Extending:
- Adding custom result types →
create-result-type.sh --type custom
- Third-party integrations →
references/plugin-system.md
- Performance optimization →
references/virtual-scrolling.md
- Analytics/telemetry →
references/analytics.md