Zetta v1.6

Components · Overlays & menus

Menu

A vertical list of navigation items or commands on a popover surface — used standalone (sidebar, settings list) or inside a popover. Distinct from a button-triggered Dropdown. Supports sections, separators, shortcuts, a selected item, and destructive items.

Preview

Build with the skill

No package to install — hand this to your AI to generate or migrate the component in your stack.

Prompt for your AI
Apply the Zetta "Menu" 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 `menu` spec (variants: item, section, separator, danger) and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `menu` 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

╭─────────────────────────────╮
│ SECTION TITLE               │  ← menu-section-title
│ ─────────────────────────── │  ← menu-separator
│ 🏠  Home                    │  ← menu-item
│ ★   Starred          ⌘K    │  ← menu-item with shortcut
│ ─────────────────────────── │
│ 🗑  Delete                  │  ← menu-item-danger
╰─────────────────────────────╯
State Visual
Closed Trigger at rest
Open Panel visible, items listed
Item hover {colors.surface-muted} fill on hovered item
Item focus {colors.surface-muted} fill + focus outline on item
Item selected {colors.primary-bg} fill, check icon prefix
Item disabled {colors.disabled-text}, not-allowed cursor
Danger item hover {colors.danger-bg} fill, {colors.danger} text

When to use

  • Sidebar navigation item lists.
  • Context menus (right-click or kebab-menu triggered).
  • Settings or preference panels with a list of options.
  • Command palette result lists.

When not to use

  • A single list of actions triggered by a button — use Dropdown.
  • Tab-like navigation between panels — use Tabs.

Do

  • Group related items with menu-section and a short section title.
  • Use menu-separator between unrelated groups.
  • Show keyboard shortcuts with menu-item-shortcut when available.
  • Use menu-item-danger only for destructive, irreversible actions.

Don't

  • Don't nest menus more than one level deep in a popover.
  • Don't put more than 10 items in a single section without grouping.
  • Item labels: noun or verb phrase, title case. "Project Settings", "Delete Project".
  • Section titles: uppercase, 1–2 words. "WORKSPACE", "RECENT".
  • Keyboard shortcuts: display with system-appropriate modifier (⌘ on Mac, Ctrl on Windows).

Keyboard

Key Behavior
Tab Move focus to the menu trigger
Enter / Space Open the menu
Up / Down Arrow Navigate between menu items
Home / End Jump to first / last item
Enter Activate the focused item
Escape Close the menu, return focus to trigger

Accessibility

  • ARIA role: role="menu" on container; role="menuitem" on each item.
  • Selected item: aria-checked="true" for checkbox-style selection; aria-current="page" for navigation.
  • Disabled items: aria-disabled="true" — keep in DOM and tab order so screen readers can announce them.
  • Sections: role="group" with aria-labelledby pointing to the section title.

Spec

Values and token references resolved straight from the Zetta spec.

menu
backgroundColor
{colors.popover}
borderColor
{colors.hairline}
borderWidth
1px
borderRadius
{rounded.base}
shadow
{elevation.shadow.overlay}
padding
{spacing.xs}
minWidth
200px
menu-section
paddingY
{spacing.xs}
menu-section-title
fontFamily
Geist
fontSize
11px
fontWeight
500
textColor
{colors.muted}
textTransform
uppercase
letterSpacing
0.06em
paddingX
{spacing.sm}
paddingY
{spacing.xs}
menu-separator
height
1px
backgroundColor
{colors.hairline}
marginY
{spacing.xs}
menu-item
display
flex
alignItems
center
gap
{spacing.sm}
paddingX
{spacing.sm}
paddingY
{spacing.xs}
borderRadius
{rounded.sm}
fontFamily
Geist
fontSize
14px
fontWeight
400
lineHeight
1.40
textColor
{colors.ink}
iconColor
{colors.muted}
iconSize
{icons.sizeMap.md}
cursor
pointer
minHeight
32px
menu-item-hover
backgroundColor
{colors.primary-bg}
textColor
{colors.primary}
menu-item-active
backgroundColor
{colors.surface-pressed}
menu-item-selected
backgroundColor
{colors.primary-bg}
textColor
{colors.primary}
iconColor
{colors.primary}
fontWeight
500
menu-item-danger
textColor
{colors.danger}
iconColor
{colors.danger}
menu-item-danger-hover
backgroundColor
{colors.danger-bg}
menu-item-disabled
textColor
{colors.disabled-text}
iconColor
{colors.disabled-text}
cursor
not-allowed
menu-item-focus
outline
2px solid {colors.border-focus}
outlineOffset
-2px
menu-item-shortcut
marginLeft
auto
fontSize
12px
fontFamily
Geist Mono
textColor
{colors.muted}