# Implementing Command Palettes

Use when building Cmd+K command palettes in React - covers keyboard navigation with...

- Repository: https://github.com/AgentWorkforce/relay (1088 stars)
- Category: Engineering
- License: Apache-2.0
- Last updated: 2026-11-01
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add AgentWorkforce/relay --skill implementing-command-palettes -g -a claude-code -y`
Codex: `npx skills add AgentWorkforce/relay --skill implementing-command-palettes -g -a codex -y`
Cursor: `npx skills add AgentWorkforce/relay --skill implementing-command-palettes -g -a cursor -y`
Gemini CLI: `npx skills add AgentWorkforce/relay --skill implementing-command-palettes -g -a gemini-cli -y`

## Description

Use when building Cmd+K command palettes in React - covers keyboard navigation with arrow keys, keeping selected items in view with scrollIntoView, filtering with shortcut matching, and preventing infinite re-renders from reference instability

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# Implementing Command Palettes

## Overview

Command palettes (Cmd+K / Ctrl+K) need precise keyboard navigation, scroll behavior, and stable references to avoid re-render loops. This skill covers the mechanical patterns that make command palettes feel responsive.

## When to Use

- Building a Cmd+K command palette in React
- Implementing arrow key navigation with visual selection
- Keeping selected items visible during keyboard navigation
- Filtering commands by label text AND keyboard shortcuts
- Experiencing infinite re-renders when commands update

## Quick Reference

| Feature           | Implementation                                             |
| ----------------- | ---------------------------------------------------------- |
| Arrow navigation  | Track `selectedIndex`, clamp with `Math.min/max`           |
| Keep in view      | `scrollIntoView({ block: 'nearest', behavior: 'smooth' })` |
| Shortcut matching | Strip spaces from shortcuts, match against query           |
| Stable icons      | Define icon elements outside component                     |
| Stable handlers   | `useCallback` + `noop` constant for disabled states        |

## Keyboard Navigation

### Index Management

```tsx
const [selectedIndex, setSelectedIndex] = useState(0);

useEffect(() => {
  if (!isOpen) return;

  const handleKeyDown = (e: KeyboardEvent) => {
    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault();
        // Clamp to last item
        setSelectedIndex((prev) => Math.min(prev + 1, filteredItems.length - 1));
        break;
      case 'ArrowUp':
        e.preventDefault();
        // Clamp to first item
        setSelectedIndex((prev) => Math.max(prev - 1, 0));
        break;
      case 'Enter':
        e.preventDefault();
        if (filteredItems[selectedIndex]) {
          executeCommand(filteredItems[selectedIndex]);
          close();
        }
        break;
      case 'Escape':
        e.preventDefault();
        close();
        break;
    }
  };

The rest: https://github.com/AgentWorkforce/relay/blob/HEAD/.claude/skills/implementing-command-palettes/SKILL.md
