Zetta v1.6

Components · Overlays & menus

Context menu

Right-click triggered contextual action menu. Split from zetta-overlay-v1_4.md (removed in v1.5) in v1.4.

Preview

Right-click this area

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 "Context 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 `context-menu` spec and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `context-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

         [right-click target]
                   ↓ cursor position
┌─────────────────────────────┐
│  [icon] Open                │
│  [icon] Edit                │
│  ─────────────────────────  │
│  [icon] Duplicate           │
│  [icon] Rename              │
│  ─────────────────────────  │
│  [icon] Delete              │  ← context-menu-item-danger
└─────────────────────────────┘
State Visual
Closed Not rendered
Open Panel at cursor coordinates, shadow applied
Item hover {colors.primary-bg} fill, {colors.primary} text
Item focus {colors.primary-bg} fill + focus outline
Danger item hover {colors.danger-bg} fill, {colors.danger-text} text
Item disabled {colors.disabled-text}, not-allowed cursor
Sub-menu trigger hover Shows chevron, child panel opens on hover/Enter

When to use

  • Table row right-click actions (open, edit, duplicate, delete).
  • Canvas or workspace element right-click.
  • File or resource right-click in a file manager.

When not to use

  • Primary actions — always surface via buttons or explicit UI.
  • As the only way to perform an action — right-click is not discoverable for keyboard and touch users.

Do

  • Mirror the most important actions in visible UI (toolbar buttons or icon buttons).
  • Always place destructive items (delete) at the bottom, separated by a divider.
  • Limit to 8–10 items. More → group into sub-menus.

Don't

  • Don't rely on context menu as the sole access point for any action.
  • Don't nest more than one level of sub-menus.
  • Item labels: verb + noun. "Edit record", "Duplicate", "Delete project".
  • Danger item: specific destructive label. "Delete project" not "Delete".
  • Sub-menu trigger label: noun describing the group. "Export as", "Move to".
  • Separator: group related items. Safety actions (delete) always in their own group at the bottom.

Keyboard

Key Behavior
Right-click / ⇧F10 Open context menu
Up / Down Arrow Navigate items
Right Arrow Open sub-menu
Left Arrow Close sub-menu, return to parent
Enter Activate item
Escape Close menu

Accessibility

  • role="menu" on the panel, role="menuitem" on items.
  • role="menuitem" with aria-haspopup="menu" on sub-menu triggers.
  • aria-disabled="true" on disabled items (still focusable).
  • Focus returns to the trigger element on close.

Spec

Values and token references resolved straight from the Zetta spec.

context-menu
backgroundColor
{colors.popover}
textColor
{colors.popover-foreground}
borderColor
{colors.hairline}
borderWidth
1px
borderRadius
{rounded.base}
shadow
{elevation.shadow.overlay}
padding
6px
zIndex
{elevation.z-index.popup}
minWidth
180px
maxWidth
280px
context-menu-item
paddingX
{spacing.sm}
paddingY
{spacing.xs}
borderRadius
{rounded.sm}
fontFamily
Geist
fontSize
14px
fontWeight
400
textColor
{colors.ink}
cursor
pointer
display
flex
alignItems
center
gap
{spacing.sm}
minHeight
32px
context-menu-item-hover
backgroundColor
{colors.primary-bg}
textColor
{colors.primary}
context-menu-item-focus
backgroundColor
{colors.primary-bg}
outline
2px solid {colors.border-focus}
outlineOffset
-2px
context-menu-item-danger
textColor
{colors.danger-text}
context-menu-item-danger-hover
backgroundColor
{colors.danger-bg}
textColor
{colors.danger-text}
context-menu-item-disabled
textColor
{colors.disabled-text}
cursor
not-allowed
context-menu-separator
height
1px
backgroundColor
{colors.hairline}
marginY
4px
context-menu-sub-trigger
chevronColor
{colors.muted}
chevronSize
14px
context-menu-sub-content
marginLeft
2px