Components · Overlays & menus
Command palette
Keyboard-driven global search and command launcher. Split from zetta-overlay-v1_4.md (removed in v1.5) in v1.4.
Preview
Go to Foundations
Go to Components
Go to Tokens
Actions
Toggle dark theme
Copy current URL
Open settings
No commands match.
Build with the skill
No package to install — hand this to your AI to generate or migrate the component in your stack.
Apply the Zetta "Command palette" component to this project using the zetta-design-md skill.
WHEN TO USE
- Migrating or fixing existing code (the common case): audit the current implementation against the `command-palette` spec and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `command-palette` spec in this project's stack.
AUDIT & FIX (when the component already exists)
Compare it to the skill's spec and fix, don't just append: hardcoded colors/hex, off-scale radius, wrong fonts, dark/navy fills, shadows used in place of borders (or missing borders), brand lime used as a CTA or interaction (must be primary indigo), and any missing or wrong hover / focus / active / disabled / invalid state or missing 2px focus ring. Replace each with the correct Zetta token.
ALWAYS
- Pull the authoritative spec and tokens from the skill — never guess or hardcode values.
- Use this project's own component conventions and framework idioms.
- Honor the Zetta guardrails (brand = identity only, primary = interaction, shadows for overlays) and verify in Light, Dark, and Accessibility. Anatomy & rules
┌──────────────────────────────────────────────┐
│ 🔍 Search commands… │ ← command-palette-input (48px)
├──────────────────────────────────────────────┤
│ RECENT │ ← command-palette-group-label
│ [icon] Open settings ⌘, │ ← command-palette-item
│ [icon] Create new project ⌘N │
│───────────────────────────────────────────── │
│ NAVIGATION │
│ [icon] Go to Dashboard │
│ [icon] Go to Members │
└──────────────────────────────────────────────┘
| State | Visual |
|---|---|
| Closed | Not rendered |
| Open | Full-width modal over blanket, input focused |
| Typing | Results filter in real time |
| Item hover | {colors.accent} fill |
| Item focused | {colors.accent} fill + focus outline |
| Item selected | {colors.primary} text, bold |
| Empty | "No results for '[query]'" centered message |
When to use
- Global command launcher accessible from anywhere in the product.
- Navigation shortcut for power users.
When not to use
- Context-specific search — use a search input within that view.
- Single-purpose action — use a button or dropdown.
Do
- Open via
⌘K(Mac) /Ctrl+K(Windows) keyboard shortcut. - Show recent commands at the top before the user types.
- Group commands by category with section labels.
- Include keyboard shortcut hints right-aligned in muted text.
- Command labels: verb + noun. "Create project", "Open settings", "Go to dashboard".
- Group labels: short noun. "Recent", "Navigation", "Actions". All caps.
- Empty state: "No results for '[query]'." — include the query in the message.
- Placeholder: "Search commands…" or "Search and navigate…".
Keyboard
| Key | Behavior |
|---|---|
⌘K / Ctrl+K |
Open command palette |
Up / Down Arrow |
Navigate items |
Enter |
Execute focused command |
Escape |
Close palette |
Type |
Filter results in real time |
Accessibility
role="dialog"on the palette panel,aria-modal="true",aria-label="Command palette".role="combobox"on the input,aria-controls="results-id",aria-expanded="true".role="listbox"on the results list,role="option"on each item.aria-activedescendanton the input, pointing to the focused item.- Focus trap inside palette while open.
aria-live="polite"region announces result count: "5 results."
Spec
Values and token references resolved straight from the Zetta spec.
command-palette
- backgroundColor
- {colors.popover}
- textColor
- {colors.popover-foreground}
- borderColor
- {colors.hairline}
- borderWidth
- 1px
- borderRadius
- {rounded.base}
- shadow
- {elevation.shadow.overlay}
- maxWidth
- 560px
- width
- 100%
- display
- flex
- flexDirection
- column
- overflow
- hidden
command-palette-input
- height
- 48px
- paddingX
- 16px
- textColor
- {colors.ink}
- placeholderColor
- {colors.placeholder}
- fontFamily
- Geist
- fontSize
- 14px
- borderBottomColor
- {colors.hairline}
- borderBottomWidth
- 1px
command-palette-item
- textColor
- {colors.ink}
- fontFamily
- Geist
- fontSize
- 14px
- minHeight
- 40px
- paddingX
- 14px
- paddingY
- 12px
- borderRadius
- {rounded.base}
- display
- flex
- alignItems
- center
- gap
- 8px
- cursor
- pointer
command-palette-item-hover
- backgroundColor
- {colors.accent}
command-palette-item-focused
- backgroundColor
- {colors.accent}
- outline
- 2px solid {colors.border-focus}
- outlineOffset
- -2px
command-palette-item-selected
- textColor
- {colors.primary}
- fontWeight
- 500
command-palette-list
- overflowY
- auto
- maxHeight
- 320px
- padding
- 6px
command-palette-empty
- textColor
- {colors.muted}
- fontFamily
- Geist
- fontSize
- 14px
- textAlign
- center
- padding
- {spacing.md}
command-palette-group-label
- textColor
- {colors.placeholder}
- fontFamily
- Geist
- fontSize
- 11px
- fontWeight
- 600
- textTransform
- uppercase
- letterSpacing
- 0.06em
- paddingX
- 14px
- paddingY
- 6px