Components · Extended
Command Palette
A keyboard-first search overlay — press ⌘K or Ctrl+K anywhere on this site right now to see it. Extremely common in developer tools and dashboards (this manual's own most-used interaction after page links), but absent from Instagram's own consumer product, which has no keyboard-driven power-user surface.
Live
Try it — this page's own header wires it up
This isn't a demo recreation. Press ⌘K / Ctrl+K, or the / key, right now — the same SearchPalette component documented below will open.
Keyboard model
Three shortcuts, one guard condition
⌘K / Ctrl+K
Toggles the palette open/closed from anywhere, including while focused inside a text field — this shortcut always wins.
/ (slash)
Opens the palette, but only when focus is NOT already inside an <input> or <textarea> — otherwise a user typing a slash character into a real field would be interrupted.
Escape
Closes the palette (and, doing double duty, also closes the mobile nav drawer if that's open instead).
↑ / ↓
Moves the active-result index, clamped to the result list bounds — never wraps past the first/last item.
Enter
Navigates to the currently active result.
function onKeyDown(e) {
const tag = document.activeElement?.tagName;
const isTyping = tag === "INPUT" || tag === "TEXTAREA";
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
e.preventDefault();
setSearchOpen((v) => !v);
} else if (e.key === "/" && !isTyping) {
e.preventDefault();
setSearchOpen(true);
} else if (e.key === "Escape") {
setSearchOpen(false);
setMobileNavOpen(false);
}
}Spec
Overlay and palette surface
Overlay backdrop
rgba(--shadow-rgb, 0.5) + 6px backdrop-filter blur — dims and softens page content without hiding it entirely
Overlay entrance
Simple opacity fade, --duration-micro (150ms), --ease-glide
Palette position
Fixed, 12vh from the top — high enough to feel keyboard-reachable, not vertically centered like a modal dialog
Palette entrance
translateY(-12px) scale(0.98) → translateY(0) scale(1), --duration-reveal (666ms), --ease-settle — the same settle-in treatment used for the site's other overlay surfaces
Palette surface
560px max-width, 70vh max-height, --modal-radius, 1px separator border, a dedicated 0 12px 48px shadow heavier than any --shadow-* token (a deliberately maximal elevation for the topmost interactive layer)
Result row
10px/12px padding, --radius-md, active row gets --ig-hover-overlay tint — keyboard nav and mouse hover share the exact same active-state style
Z-index
var(--z-palette) — the highest confirmed layer in this system, above even the mobile nav drawer
Do
- Guard text-triggerable shortcuts against active text fields — A bare / or other single-character shortcut must check document.activeElement before firing — otherwise it breaks every text field on the page.
- Let ⌘K/Ctrl+K work everywhere, unconditionally — The modifier-key combination is unambiguous — it never collides with normal typing, so it doesn't need the same guard as a bare key shortcut.
- Reuse Escape for whatever overlay is currently open — One global Escape handler that closes search AND mobile nav (whichever is active) is simpler and more predictable than per-component key listeners.
- Show the empty state only after a real query — See Empty States — don't flash 'no results' before the user has typed anything; a blank query should show a browsable default (recent/all items), not an error-adjacent empty state.
Don’t
- Don't trap body scroll without restoring it on close — Locking document.body.style.overflow while the palette is open is correct — but the cleanup function must restore it, or every subsequent page becomes unscrollable if the component unmounts unexpectedly.
- Don't make the palette taller than ~70vh — A full-height palette starts to compete with the content it's meant to help you find quickly — cap it and let results scroll internally.