Skip to content

Command Palette Usage

Problem

A command palette needs consistent behavior across features:

  • A single open/close state
  • A predictable registry of commands (navigation + actions)
  • Grouping and disabling
  • A default keyboard trigger (Cmd/Ctrl+K)

Ad hoc implementations typically scatter command lists across the app, making discovery and maintenance difficult.

Solution

Use useCommandPalette as the centralized state/registry, then render it with the shared CommandPalette component.

  • Register an initial command set via initialCommands
  • Compose additional commands via add()/remove() at feature boundaries
  • Let the hook handle the default shortcut, or disable it and wire your own

Implementation

tsx
import React, { useMemo } from 'react'
import { useCommandPalette, type Command } from '@/shared/hooks'
import { CommandPalette } from '@/shared/ui/components/CommandPalette'

export function AppCommands() {
  const commands: Command[] = useMemo(
    () => [
      {
        id: 'go-dashboard',
        label: 'Go to Dashboard',
        group: 'Navigation',
        action: async () => {
          // navigate('/dashboard')
        },
      },
      {
        id: 'create-invoice',
        label: 'Create Invoice',
        group: 'Actions',
        action: async () => {
          // openCreateInvoiceModal()
        },
      },
    ],
    []
  )

  const palette = useCommandPalette({ initialCommands: commands })

  return (
    <CommandPalette
      open={palette.isOpen}
      onOpenChange={(open) => (open ? palette.open() : palette.close())}
      commands={palette.commands}
      groupedCommands={palette.groupedCommands}
      onSelect={(cmd) => palette.execute(cmd.id)}
    />
  )
}

Variations

  • Feature-level registration
    • Use add() on mount and remove(ids) on unmount to keep commands aligned with route lifecycle.
  • Custom trigger
  • Disabled commands
    • Set disabled: true and keep them visible but not selectable.

Accessibility considerations

  • Ensure the palette is reachable without a keyboard shortcut (provide a button).
  • Provide visible shortcut hints when possible (shortcut string).
  • Avoid triggering while typing unless intentionally configured.