components / menu

Menu

Data-driven action list with highlight, selection, and overlay containment.

Overview

What it is

This section explains the intent of the component before the implementation details.

  • Menu presents a compact list of actions tied to one trigger, typically in a contextual or command-like overlay.
  • The DK contract focuses on highlight clarity, dismissal behavior, and predictable action selection.

Aliases

action menu

Decision guide

How to choose it

Use these notes to decide quickly whether this is the right DK component for the job.

Decision guide

  • Choose Menu when the interaction should feel deliberate, documented, and reusable across product surfaces.
  • If the scenario is more specialized than the current Menu contract, prefer a simpler component or build a dedicated workflow on top of the lower-level DK primitives.

Do

  • Keep the Menu label, value, or status language direct enough to scan quickly.
  • Use the documented size and state recipes instead of inventing one-off variants in product code.

Do not

  • Do not hide the main purpose of Menu behind decorative copy or overloaded surface treatments.
  • Do not stretch Menu into a workflow it was not designed to handle just because the visuals are close.

Usage

When to use

Prefer these situations when choosing this component.

  • Use Menu when you need a short contextual list of actions tied to a trigger.
  • Use destructive styling when one option carries real risk.

Usage

When not to use

These patterns are better served by a different component or a simpler surface.

  • Do not use Menu for long searchable option lists; use Select or Combobox.
  • Do not hide the primary action of a surface inside a menu if it should be obvious.

Anti-patterns

  • Using Menu as a generic layout container instead of a purpose-built interaction or content surface.
  • Forking the documented recipe in product code instead of extending the shared DK contract.

Migration notes

  • Migrate legacy menu usage by mapping existing variants and states onto the documented DK props before porting any custom styling.
  • Treat the docs examples as the reference contract for accessibility and event behavior during adoption.

Anatomy

Structural parts

The anatomy explains which pieces matter to the recipe and accessibility model.

open affordance

trigger

Opens the menu surface.

menu overlay

surface

Contains the action list.

menu item

item

Selectable action row.

API

Public interface

The docs contract distinguishes props, DOM events, and slots so integration behavior is explicit.

Props

NameTypeDefaultDescription
openbooleanfalseControlled open state.
itemsArray<{ value: string; label: string; shortcut?: string; disabled?: boolean; destructive?: boolean }>Menu item definitions.
placement'top' | 'right' | 'bottom' | 'left''bottom'Preferred anchor placement.
size'sm' | 'md''md'Chooses the menu size recipe.
onOpenChange(detail: { open: boolean }) => voidCallback fired when the menu opens or closes.
onAction(detail: { id?: string; value?: string }) => voidCallback fired when a menu item is selected.
themeThemeContractOverrides the compiled DK theme used to resolve tokens and recipes for this component.

Events

NamePayloadDescription
openchange{ open: boolean }Fires when an overlay-style component opens or closes through user interaction.
action{ id?: string; value?: string }Fires when the component exposes a primary action and the user activates it.

Slots

NameDescription
triggerTrigger content for the menu.

Recipes

Variants, sizes, and states

These notes summarize the intended recipe surface rather than exposing raw implementation detail first.

Variants

  • bottom/top/left/right: Placement chooses the preferred anchored direction.

Sizes

  • sm: Compact menu
  • md: Default menu

States

  • closed: Menu hidden
  • open: Menu visible
  • highlighted: Keyboard-highlighted item

Accessibility

Accessibility contract

This is the behavior the component promises to assistive tech and keyboard users today.

Semantics

  • Uses menu semantics and a focused action list.

Keyboard

  • Arrow keys move through menu items, Enter commits the current item, and Escape closes the menu.

Screen readers

  • Item labels and disabled/destructive state remain understandable without color alone.

Checklist

  • Verify the visible label or title still produces a clear accessible name.
  • Verify focus remains obvious in every supported state and size.
  • Verify disabled, selected, and error states do not rely on color alone.

Implementation

Tokens and slot vars

This section shows the representative compiled slot variables that the runtime consumes for the selected design system.

root

--dk-motion-duration
200ms
--dk-menu-offset
12px

surface

--dk-menu-surface-bg
#f2f5fb
--dk-menu-surface-fg
#16181c
--dk-menu-surface-border
#95989d
--dk-menu-surface-radius
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)
--dk-menu-surface-shadow
0 10px 15px rgba(0, 0, 0, 0.06), 0 4px 6px rgba(0, 0, 0, 0.04)
--dk-menu-surface-width
260px
--dk-menu-surface-padding
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)

item

--dk-menu-item-bg
transparent
--dk-menu-item-fg
#16181c
--dk-menu-item-radius
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)
--dk-menu-item-min-height
44px
--dk-menu-item-inline-padding
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)

label

--dk-menu-label-size
clamp(1.333rem, 1.2222rem + 0.494vw, 1.667rem)
--dk-menu-label-weight
550

shortcut

--dk-menu-shortcut-size
clamp(0.75rem, 0.6875rem + 0.278vw, 0.938rem)

Implementation notes

  • Menu is action-focused in v1. Checkbox and radio menu item variants are intentionally deferred.

Implementation checklist

  • Use the public component API first and only drop to lower-level primitives when the component contract genuinely does not fit.
  • Keep theme overrides token-driven so proofs and recipes stay meaningful.
  • Verify the shipped examples and proof fixtures still represent the real product scenario you are implementing.

Examples

Copy-paste examples

Each example is intentionally practical, grouped by starter, common pattern, and edge-case coverage.

Examples
3
Depth
expanded

Starter

1 example

starter

Starter: contextual action list

A short anchored action menu.

Copy snippet

<Menu items={[{ value: 'rename', label: 'Rename' }, { value: 'archive', label: 'Archive', destructive: true }]}><svelte:fragment slot="trigger">Open menu</svelte:fragment></Menu>

Common patterns

1 example

common

Common: shortcut-aware menu

Shortcuts help power users scan faster.

Copy snippet

<Menu items={[{ value: 'duplicate', label: 'Duplicate', shortcut: '⌘D' }, { value: 'archive', label: 'Archive', shortcut: '⌘⌫' }]} />

Edge cases

1 example

edge

Edge: externally controlled menu

Control open state when a larger workflow coordinates menu visibility.

Copy snippet

<Menu open={isOpen} onOpenChange={(detail) => isOpen = detail.open} items={menuItems}><svelte:fragment slot="trigger">Open menu</svelte:fragment></Menu>

Verification

Curated proof fixtures

Proofs stay visible in the docs so the system shows what it can guarantee, not just what it can render.

default (size=sm)

pass

size=sm

  • Contrast: 98.5 Lc
  • Rows: 44px
  • Surface: 260x280

default (size=md)

pass

size=md

  • Contrast: 98.5 Lc
  • Rows: 44px
  • Surface: 260x280

default (size=lg)

pass

size=lg

  • Contrast: 98.5 Lc
  • Rows: 44px
  • Surface: 260x280

selected (size=sm)

pass

size=sm

  • Contrast: 97.9 Lc
  • Rows: 44px
  • Surface: 260x280

selected (size=md)

pass

size=md

  • Contrast: 97.9 Lc
  • Rows: 44px
  • Surface: 260x280

selected (size=lg)

pass

size=lg

  • Contrast: 97.9 Lc
  • Rows: 44px
  • Surface: 260x280