Menus
Menus display a list of choices on temporary surfaces, typically triggered by buttons or context actions. They allow users to select from a set of options without cluttering the interface.
Installation
Copy the menu CSS from styles/docs.css or include the Standard stylesheet:
<link rel="stylesheet" href="standard.min.css">
Then use menu classes in your HTML:
<div class="Menu">
<button class="Menu-item">Edit</button>
<button class="Menu-item">Delete</button>
</div>
Usage
The base .Menu class provides the menu container styling. Add .Menu--open to show the menu, and use .Menu-item for each action.
<div class="Menu Menu--open" style="position: relative; max-width: 180px;">
<button class="Menu-item">Edit</button>
<button class="Menu-item">Duplicate</button>
<button class="Menu-item">Archive</button>
<button class="Menu-item">Delete</button>
</div>
Examples
Basic Menu
A simple dropdown menu with clickable items.
<div class="Menu-demo">
<button class="Button Button--secondary" onclick="this.nextElementSibling.classList.toggle('Menu--open')">
Options
<i class="ph ph-caret-down"></i>
</button>
<div class="Menu Menu--open" style="position: relative; top: var(--space-2);">
<button class="Menu-item">Edit</button>
<button class="Menu-item">Duplicate</button>
<button class="Menu-item">Archive</button>
<button class="Menu-item">Delete</button>
</div>
</div>
Menu with Icons
Add leading icons to menu items for visual recognition.
<div class="Menu Menu--open" style="max-width: 200px;">
<button class="Menu-item">
<i class="Menu-item-icon ph ph-pencil"></i>
Edit
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-copy"></i>
Duplicate
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-archive"></i>
Archive
</button>
<div class="Menu-divider"></div>
<button class="Menu-item Menu-item--danger">
<i class="Menu-item-icon ph ph-trash"></i>
Delete
</button>
</div>
Menu with Shortcuts
Display keyboard shortcuts alongside menu items.
<div class="Menu Menu--open" style="max-width: 240px;">
<button class="Menu-item">
<span class="Menu-item-text">Undo</span>
<span class="Menu-item-shortcut">⌘Z</span>
</button>
<button class="Menu-item">
<span class="Menu-item-text">Redo</span>
<span class="Menu-item-shortcut">⇧⌘Z</span>
</button>
<div class="Menu-divider"></div>
<button class="Menu-item">
<span class="Menu-item-text">Cut</span>
<span class="Menu-item-shortcut">⌘X</span>
</button>
<button class="Menu-item">
<span class="Menu-item-text">Copy</span>
<span class="Menu-item-shortcut">⌘C</span>
</button>
<button class="Menu-item">
<span class="Menu-item-text">Paste</span>
<span class="Menu-item-shortcut">⌘V</span>
</button>
<div class="Menu-divider"></div>
<button class="Menu-item">
<span class="Menu-item-text">Select All</span>
<span class="Menu-item-shortcut">⌘A</span>
</button>
</div>
Menu with Sections
Group related items with headers.
<div class="Menu Menu--open" style="max-width: 220px;">
<div class="Menu-header">View</div>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-squares-four"></i>
Grid View
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-list"></i>
List View
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-columns"></i>
Column View
</button>
<div class="Menu-header">Sort By</div>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-calendar"></i>
Date Modified
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-text-aa"></i>
Name
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-file"></i>
Size
</button>
</div>
Checkable Menu
Menu items with checkboxes or radio buttons for toggling options.
<div style="display: flex; gap: var(--space-6);">
<div class="Menu Menu--open" style="min-width: 180px;">
<div class="Menu-header">Options</div>
<label class="Menu-item Menu-item--checkbox">
<input type="checkbox" checked>
<span class="Menu-item-text">Show Hidden Files</span>
</label>
<label class="Menu-item Menu-item--checkbox">
<input type="checkbox">
<span class="Menu-item-text">Show Extensions</span>
</label>
<label class="Menu-item Menu-item--checkbox">
<input type="checkbox" checked>
<span class="Menu-item-text">Show Preview</span>
</label>
</div>
<div class="Menu Menu--open" style="min-width: 160px;">
<div class="Menu-header">Sort Order</div>
<label class="Menu-item Menu-item--radio">
<input type="radio" name="sort" checked>
<span class="Menu-item-text">Ascending</span>
</label>
<label class="Menu-item Menu-item--radio">
<input type="radio" name="sort">
<span class="Menu-item-text">Descending</span>
</label>
</div>
</div>
Submenu
Menu items that expand to show nested options.
<div class="Menu Menu--open" style="max-width: 200px;">
<button class="Menu-item">
<i class="Menu-item-icon ph ph-file-plus"></i>
New
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-folder-open"></i>
Open
</button>
<button class="Menu-item Menu-item--submenu">
<i class="Menu-item-icon ph ph-clock-counter-clockwise"></i>
<span class="Menu-item-text">Recent</span>
<i class="Menu-item-chevron ph ph-caret-right"></i>
</button>
<div class="Menu-divider"></div>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-floppy-disk"></i>
Save
</button>
<button class="Menu-item Menu-item--submenu">
<i class="Menu-item-icon ph ph-export"></i>
<span class="Menu-item-text">Export As</span>
<i class="Menu-item-chevron ph ph-caret-right"></i>
</button>
</div>
Compact Menu
A denser menu variant for space-constrained areas or toolbars.
<div class="Menu Menu--open Menu--compact" style="max-width: 160px;">
<button class="Menu-item">
<i class="Menu-item-icon ph ph-pencil"></i>
Edit
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-copy"></i>
Copy
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-share"></i>
Share
</button>
<div class="Menu-divider"></div>
<button class="Menu-item Menu-item--danger">
<i class="Menu-item-icon ph ph-trash"></i>
Delete
</button>
</div>
Menu with Descriptions
Add secondary text for more context on complex actions.
<div class="Menu Menu--open" style="max-width: 280px;">
<button class="Menu-item Menu-item--multiline">
<i class="Menu-item-icon ph ph-user-circle"></i>
<div class="Menu-item-content">
<span class="Menu-item-title">Profile</span>
<span class="Menu-item-description">View and edit your profile</span>
</div>
</button>
<button class="Menu-item Menu-item--multiline">
<i class="Menu-item-icon ph ph-gear"></i>
<div class="Menu-item-content">
<span class="Menu-item-title">Settings</span>
<span class="Menu-item-description">Manage preferences</span>
</div>
</button>
<button class="Menu-item Menu-item--multiline">
<i class="Menu-item-icon ph ph-bell"></i>
<div class="Menu-item-content">
<span class="Menu-item-title">Notifications</span>
<span class="Menu-item-description">Configure alerts</span>
</div>
</button>
<div class="Menu-divider"></div>
<button class="Menu-item Menu-item--danger">
<i class="Menu-item-icon ph ph-sign-out"></i>
Sign Out
</button>
</div>
Context Menu
Right-click style context menu for in-place actions.
<div style="position: relative; padding: var(--space-8); background: var(--bg-s); border-radius: var(--r-m); text-align: center; color: var(--fg-3);">
<span>Right-click area (simulated)</span>
<div class="Menu Menu--open Menu--context" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
<button class="Menu-item">
<i class="Menu-item-icon ph ph-arrow-left"></i>
Back
</button>
<button class="Menu-item" disabled>
<i class="Menu-item-icon ph ph-arrow-right"></i>
Forward
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-arrow-clockwise"></i>
Reload
</button>
<div class="Menu-divider"></div>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-code"></i>
View Source
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-magnifying-glass"></i>
Inspect
</button>
</div>
</div>
Disabled Items
Menu items that are not currently available.
<div class="Menu Menu--open" style="max-width: 200px;">
<button class="Menu-item">
<i class="Menu-item-icon ph ph-pencil"></i>
Edit
</button>
<button class="Menu-item" disabled>
<i class="Menu-item-icon ph ph-scissors"></i>
Cut
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-copy"></i>
Copy
</button>
<button class="Menu-item" disabled>
<i class="Menu-item-icon ph ph-clipboard"></i>
Paste
</button>
</div>
Common Patterns
User Account Menu
<div style="display: flex; justify-content: flex-end;">
<div style="position: relative;">
<button class="Button Button--ghost" style="display: flex; align-items: center; gap: var(--space-2);">
<div style="width: 28px; height: 28px; border-radius: 50%; background: oklch(65% 0.15 250); color: white; display: flex; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: 600;">SC</div>
<span>Sarah Chen</span>
<i class="ph ph-caret-down"></i>
</button>
<div class="Menu Menu--open" style="position: relative; top: var(--space-2); min-width: 200px;">
<button class="Menu-item">
<i class="Menu-item-icon ph ph-user"></i>
Profile
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-gear"></i>
Settings
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-credit-card"></i>
Billing
</button>
<div class="Menu-divider"></div>
<button class="Menu-item Menu-item--danger">
<i class="Menu-item-icon ph ph-sign-out"></i>
Sign Out
</button>
</div>
</div>
</div>
Toolbar Actions Menu
<div style="display: flex; gap: var(--space-2); align-items: flex-start;">
<button class="Button Button--secondary Button--small">
<i class="ph ph-pencil"></i> Edit
</button>
<div style="position: relative;">
<button class="Button Button--secondary Button--small">
<i class="ph ph-dots-three"></i>
</button>
<div class="Menu Menu--open Menu--compact" style="position: relative; top: var(--space-1); min-width: 160px;">
<button class="Menu-item">
<i class="Menu-item-icon ph ph-copy"></i>
Duplicate
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-archive"></i>
Archive
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-share"></i>
Share
</button>
<div class="Menu-divider"></div>
<button class="Menu-item Menu-item--danger">
<i class="Menu-item-icon ph ph-trash"></i>
Delete
</button>
</div>
</div>
</div>
Table Row Actions
<div style="display: flex; align-items: center; justify-content: space-between; padding: var(--space-3); border: 1px solid var(--bd); border-radius: var(--r-m); max-width: 480px;">
<div style="display: flex; align-items: center; gap: var(--space-3);">
<i class="ph ph-file-text" style="color: var(--fg-3);"></i>
<div>
<div style="font-weight: 500; font-size: 0.9rem;">Project Proposal.pdf</div>
<div style="font-size: 0.8rem; color: var(--fg-3);">2.4 MB · Jan 15, 2026</div>
</div>
</div>
<div style="position: relative;">
<div class="Menu Menu--open Menu--compact" style="position: relative; min-width: 140px;">
<button class="Menu-item">
<i class="Menu-item-icon ph ph-download"></i>
Download
</button>
<button class="Menu-item">
<i class="Menu-item-icon ph ph-share"></i>
Share
</button>
<div class="Menu-divider"></div>
<button class="Menu-item Menu-item--danger">
<i class="Menu-item-icon ph ph-trash"></i>
Delete
</button>
</div>
</div>
</div>
Customization
Override menu styles using CSS custom properties:
/* Custom menu appearance */
.Menu {
--menu-bg: var(--bg);
--menu-border: var(--border-primary);
--menu-shadow: var(--shadow-lg);
--menu-radius: var(--radius-lg);
}
/* Custom item styling */
.Menu-item {
--menu-item-padding: var(--space-2) var(--space-3);
--menu-item-hover: var(--bg-s);
}
/* Danger variant color */
.Menu-item--danger {
--menu-item-color: var(--color-danger);
}
/* Custom compact variant */
.Menu--compact .Menu-item {
--menu-item-padding: var(--space-1) var(--space-2);
font-size: var(--text-sm);
}
/* Wider menu */
.Menu--wide {
min-width: 280px;
}
API Reference
Container Classes
| Class | Description |
|---|---|
.Menu |
Base menu container (hidden by default) |
.Menu--open |
Shows the menu (display: block) |
.Menu--compact |
Denser padding for compact layouts |
.Menu--context |
Context menu styling (absolute positioning) |
Item Classes
| Class | Description |
|---|---|
.Menu-item |
Clickable menu item (use on button/a/label) |
.Menu-item--danger |
Destructive action styling (red text) |
.Menu-item--checkbox |
Checkbox item (use on label) |
.Menu-item--radio |
Radio item (use on label) |
.Menu-item--submenu |
Item with nested submenu indicator |
.Menu-item--multiline |
Item with title and description |
Item Content Classes
| Class | Description |
|---|---|
.Menu-item-icon |
Leading icon in menu item |
.Menu-item-text |
Main text label (required with shortcuts) |
.Menu-item-shortcut |
Keyboard shortcut display (right-aligned) |
.Menu-item-chevron |
Submenu indicator arrow |
.Menu-item-content |
Wrapper for multiline items |
.Menu-item-title |
Primary text in multiline item |
.Menu-item-description |
Secondary text in multiline item |
Structural Classes
| Class | Description |
|---|---|
.Menu-header |
Section header (non-interactive) |
.Menu-divider |
Visual separator between groups |
Data Attributes
| Attribute | Description |
|---|---|
disabled |
Disables the menu item (grayed out, not clickable) |
CSS Reference
/* Menu Container */
.Menu {
display: none;
flex-direction: column;
background: var(--bg);
border: 1px solid var(--bd);
border-radius: var(--r-m);
padding: var(--space-1);
box-shadow: 0 4px 12px oklch(0% 0 0 / 0.1);
min-width: 160px;
z-index: 100;
}
.Menu--open {
display: flex;
}
/* Menu Item */
.Menu-item {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-2) var(--space-3);
border: none;
background: none;
cursor: pointer;
font-size: 0.9rem;
color: var(--fg);
border-radius: var(--r-s);
width: 100%;
text-align: left;
transition: background-color 0.1s;
}
.Menu-item:hover {
background-color: var(--bg-s);
}
.Menu-item:focus-visible {
outline: 2px solid var(--accent);
outline-offset: -2px;
}
/* Danger Item */
.Menu-item--danger {
color: oklch(55% 0.2 25);
}
.Menu-item--danger:hover {
background-color: oklch(55% 0.2 25 / 0.1);
}
/* Disabled Item */
.Menu-item:disabled,
.Menu-item[aria-disabled="true"] {
opacity: 0.5;
cursor: not-allowed;
}
.Menu-item:disabled:hover {
background: none;
}
/* Item Icon */
.Menu-item-icon {
font-size: 1.1rem;
flex-shrink: 0;
color: var(--fg-3);
}
.Menu-item--danger .Menu-item-icon {
color: oklch(55% 0.2 25);
}
/* Item Text & Shortcut */
.Menu-item-text {
flex: 1;
}
.Menu-item-shortcut {
font-size: 0.75rem;
color: var(--fg-3);
margin-left: auto;
}
/* Submenu */
.Menu-item-chevron {
font-size: 0.8rem;
color: var(--fg-3);
margin-left: auto;
}
/* Multiline Item */
.Menu-item--multiline {
align-items: flex-start;
padding: var(--space-3);
}
.Menu-item-content {
display: flex;
flex-direction: column;
gap: var(--space-1);
}
.Menu-item-title {
font-weight: 500;
}
.Menu-item-description {
font-size: 0.8rem;
color: var(--fg-3);
}
/* Checkbox / Radio Items */
.Menu-item--checkbox,
.Menu-item--radio {
gap: var(--space-2);
}
/* Divider */
.Menu-divider {
height: 1px;
background: var(--bd);
margin: var(--space-1) 0;
}
/* Header */
.Menu-header {
padding: var(--space-2) var(--space-3);
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--fg-3);
}
/* Compact Variant */
.Menu--compact .Menu-item {
padding: var(--space-1) var(--space-2);
font-size: 0.85rem;
}
/* Context Menu */
.Menu--context {
position: absolute;
}
Accessibility
Keyboard Support
| Key | Action |
|---|---|
| Enter / Space | Activates focused menu item |
| Escape | Closes the menu |
| Arrow Down | Moves focus to next item |
| Arrow Up | Moves focus to previous item |
| Arrow Right | Opens submenu (if present) |
| Arrow Left | Closes submenu, returns to parent |
| Home | Moves focus to first item |
| End | Moves focus to last item |
Screen Readers
<!-- Menu trigger with aria-expanded -->
<button class="Button Button--secondary"
aria-haspopup="menu"
aria-expanded="false"
aria-controls="options-menu">
Options
<i class="ph ph-caret-down"></i>
</button>
<!-- Menu container with role -->
<div class="Menu" role="menu" id="options-menu" aria-label="Options">
<button class="Menu-item" role="menuitem">Edit</button>
<button class="Menu-item" role="menuitem">Duplicate</button>
<div class="Menu-divider" role="separator"></div>
<button class="Menu-item" role="menuitem">Delete</button>
</div>
<!-- Disabled item -->
<button class="Menu-item" role="menuitem" aria-disabled="true">
Paste
</button>
<!-- Checkbox item -->
<div class="Menu-item" role="menuitemcheckbox" aria-checked="true">
<span class="Menu-item-text">Show Hidden Files</span>
</div>
<!-- Radio group -->
<div role="group" aria-label="Sort order">
<div class="Menu-item" role="menuitemradio" aria-checked="true">
Ascending
</div>
<div class="Menu-item" role="menuitemradio" aria-checked="false">
Descending
</div>
</div>
<!-- Submenu trigger -->
<button class="Menu-item" role="menuitem" aria-haspopup="menu" aria-expanded="false">
<span class="Menu-item-text">Recent</span>
<i class="Menu-item-chevron ph ph-caret-right"></i>
</button>
Focus Management
<!-- When menu opens: -->
<!-- 1. Set aria-expanded="true" on trigger -->
<!-- 2. Move focus to first menu item -->
<!-- 3. Trap focus within menu -->
<!-- When menu closes: -->
<!-- 1. Set aria-expanded="false" on trigger -->
<!-- 2. Return focus to trigger button -->
Best Practices
Do
- ✓ Use clear, concise labels — “Delete” not “Remove this item from the list”
- ✓ Group related items — Use headers and dividers to organize
- ✓ Show keyboard shortcuts — Help power users work faster
- ✓ Use icons consistently — All items with icons, or none
- ✓ Put destructive actions last — Separated by a divider
- ✓ Close on selection — Menu should dismiss after an action
- ✓ Manage focus properly — Return focus to trigger on close
Don’t
- ✗ Nest too deeply — More than 2 levels becomes confusing
- ✗ Use menus for navigation — Use proper nav components instead
- ✗ Mix icons and no-icons — Be consistent within a menu
- ✗ Forget disabled states — Explain why items are unavailable
- ✗ Make menus too wide — Keep them scannable (max ~300px)
- ✗ Put too many items — Consider breaking into sections or submenus
- ✗ Ignore touch targets — Minimum 44px height on mobile