New
Command Palette
A full-screen search overlay surfacing all navigation destinations. Triggered by ⌘K and dismissed by Escape or backdrop click.
Preview
Or press ⌘K anywhere
Keyboard shortcuts
| Key | Action |
|---|---|
| ⌘K / Ctrl+K | Open the palette (wire in consumer — not built in) |
| ↑ / ↓ | Navigate through results |
| ↵ Enter | Navigate to the highlighted result |
| Escape | Close the palette |
| Click backdrop | Close the palette |
Data source
Results are drawn from allSearchableItems exported by @/lib/navigation. This is a flat array derived from the full navigation tree with added section and group metadata.
To surface additional content (pages, actions, recent items), extend allSearchableItems or pass a custom items list to the component.
Motion
| Element | Enter | Exit |
|---|---|---|
| Backdrop | opacity 0 → 1 (200ms ease) | opacity 1 → 0 (150ms ease) |
| Panel | opacity+scale(0.97)+y(−8px) → visible, spring(500,40) | opacity+scale → hidden (150ms ease) |
Implementation
CommandPaletteUsage.tsx
tsx
"use client";
import { useState, useEffect } from "react";
import { CommandPalette } from "@/site/search/CommandPalette";
export function AppShell({ children }: { children: React.ReactNode }) {
const [open, setOpen] = useState(false);
// ⌘K / Ctrl+K global shortcut
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
e.preventDefault();
setOpen((v) => !v);
}
};
document.addEventListener("keydown", handler);
return () => document.removeEventListener("keydown", handler);
}, []);
return (
<>
{children}
<CommandPalette open={open} onClose={() => setOpen(false)} />
</>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
open* | boolean | — | Controls whether the palette is visible. Mount/unmount is handled internally via AnimatePresence. |
onClose* | () => void | — | Called when the user presses Escape, clicks the backdrop, or activates a result. |
ARIA roles
| Element | Role | Key attributes |
|---|---|---|
| Container | dialog | aria-modal='true', aria-label |
| Search input | combobox | aria-expanded, aria-controls, aria-activedescendant |
| Results list | listbox | aria-label |
| Result item | option | aria-selected |
Keyboard
| Key | Action |
|---|---|
| ⌘K / Ctrl+K | Open the command palette |
| Arrow Down / Up | Move focus between results |
| Enter | Execute the focused result |
| Escape | Close the command palette |
| Tab | Cycle forward through results (same as Arrow Down) |
Accessibility
- →Panel uses role="dialog" and aria-modal="true" to trap assistive technology focus.
- →Input auto-focuses on open so users can type immediately without tabbing.
- →Results list uses role="listbox"; highlighted item uses aria-selected.
- →Backdrop click and Escape both close the dialog consistently.
- →Keyboard navigation (↑↓ Enter Escape) is handled via document-level keydown listeners that are cleaned up on unmount.
- →⌘K binding is implemented in the consumer, not in the component — giving teams flexibility to use a different shortcut.