Menu
A menu opens a short list of commands from a button, such as Rename, Duplicate, and Delete, and closes once one is chosen. On opening, where focus lands decides how fast a keyboard user reaches a command, and typing a letter jumps to a matching item with no key handler to write. Each button below opens a different menu.
Reference docs
Choosing a pop-up surface
Five kinds of surface open over the page for a moment. Each suits a different job:
- Dialog: a question the reader must answer before going on, such as Discard unsaved changes?
- Popover: extra content opened from a control and dismissed by clicking away, such as a small settings panel.
- Menu: a short list of commands opened from a button, such as Rename, Duplicate, Delete.
- Plain tooltip: a short label shown on hover or focus, such as what an icon button does.
- Rich tooltip: a heading, a few lines of text and an optional action shown next to the element it describes, such as what a new feature does.
Three jobs belong elsewhere. A message about something that just happened is a toast, content that stays on the page is a card, and a short set of creation actions opened from a floating button is a FAB menu.
Built in
- The arrow keys, Home, and End move focus through the items, and
stops the wrap at either end.no-navigation-wrap - Type-ahead finds an item by its label, and
sets the pause that resets it.typeahead-delay - Arrow keys on the button open the menu at its first or last item.
- A choice closes the menu and reports the item's
, index, and label invalueitem-select; on an item leaves the menu open.keep-open - Closing returns focus to where it was before the menu opened, unless
is set.skip-restore-focus - Items come from child elements or from data, with
.expressContent - An item's
startandendslots take any icon, avatar, or control, and andleading-icon-name draw an icon with no markup. Overline, supporting text, and trailing supporting text give a row up to four kinds of text.trailing-icon-name makes an item a link, andhref keeps it on screen and out of the keyboard's way.disabled- A sub-menu opens on hover after
(400 milliseconds by default), or at once on a click or tap; a choice at any level closes the whole chain, and only the outermost menu reports it.hover-open-delay
Sub-menus
A sub-menu is a kind of menu, nested in a menu or another sub-menu, and the work is split between the two.
- Shared with every menu: the items, the keyboard handling, and the design tokens.
- Taken from the menu that holds it: the choice. The outermost menu reports a choice made at any level through
item-select,input, andchange. - Set on the sub-menu itself: the two hover delays,
andhover-open-delay , and its density; a sub-menu nested in another opens with no delay, whatever its own. It does not copy density or typeahead timing from its parent, so it uses its own value or the configured default.hover-close-delay - Never present: its own animation, open action, or opening focus. A sub-menu always opens on hover and on a click of its anchor item, appears without animating, and moves focus to its first item.
A sub-menu also fires its own beforetoggle and toggle events, and they bubble to the listeners on its parent menu.
Hidden content renders when first shown
A menu keeps its items hidden until it opens. Each opening starts like the first: from the first item, with nothing pressed or highlighted, and any open sub-menu closed. The last chosen value stays. Wait for updateComplete and the hidden content has rendered, so your code can reach it at once. See Hidden content renders when first shown.
Using menus well
- Give every item a text label, and add an icon only as a companion to it.
- Start each label with a verb or name the value it sets, and keep it short enough to read at a glance.
- Use a menu for commands, and radio buttons, chips, or a select for a choice among options.
- Open a menu from a button, and word the button for what the menu holds.
- Keep the list short enough to scan at a glance, with the most used items first, and separate related groups with a divider before reaching for a sub-menu.
- Keep nesting to one level where you can, and label a sub-menu's anchor item with what the group holds, with a trailing arrow.
- Mark the current choice with a leading check icon, since the highlight follows focus and cannot mark a choice.
- Say why an item is unavailable in the interface around the menu.
- Use a link item only for a command that happens to open an address, such as Help, and keep page navigation out of menus.
These rules follow Material 3 Expressive's guidance for menus, on material.io.
Animation
animationfaded-slide
Choose expandnone
Default focus
default-focusfirst-item
Choose last-itemnone
Density
density
Choose a denser setting for a menu with many commands or a compact toolbar, and keep the standard spacing on a touch screen.
Open action
open-actionclickhover-focushover-open-delayhover-close-delay
Both delays default to 400 milliseconds and also apply to sub-menus. Choose a click for a list of commands, since a menu that opens on hover is easy to trigger by accident.
Choosing an item
Each choice closes the menu and fires item-select, which carries the item's value, its index within itemslabel.
Listen for item-select to act on a choice. It fires for a click and for the keyboard alike.
Keyboard navigation
By default, moving past the last item wraps focus to the first, and the reverse. no-navigation-wrap
Type-ahead matches the letters you type against item labels. typeahead-delay
Closing and focus
Escape, a click outside, and focus leaving the menu all close it, and focus returns to the control that was focused before. Each has a setting that changes it.
stay-open-on-outside-clickstay-open-on-focusoutskip-restore-focus
Anchors
The anchor slot holds the control that opens the menu, and the menu aligns to it. To open the menu from a control elsewhere, set anchorexternal-anchor
anchorElement
Items from data
expressContent
Use one source of items, children or data. Choose data when the commands come from a list your code already holds.
Opening from code
openshow() and hide() do the same. Use them to open a menu from a shortcut or from something other than its anchor.
The menu also closes itself on Escape and on a choice.
In a list row
A menu of row actions opens from an icon button at the end of the row. The icon button needs an accessible name that says which row it belongs to, because every row shows the same icon.
Set aria-haspopup="menu" on the icon button, since the menu does not write it.
Item text
The default slot holds the label. Three more slots add text: overline above the label, supporting-text below it, and trailing-supporting-text at the end, which suits a keyboard shortcut.
Put the words that identify the item in the default slot, because nothing else names it or feeds type-ahead.
Item icons
leading-icon-nametrailing-icon-namestart and end slots. To use another icon, an avatar, or a control, put an element in the slot itself. Slotted content wins over a named icon, and the item logs a warning.
An icon arrow that points in a reading direction needs flip-leading-icon-in-rtlflip-trailing-icon-in-rtlflip-in-rtl to an icon in a slot for the same effect.
Link items
hreftarget
In this preview, a link that opens a new tab is refused, so the second item does nothing here. On your own page it opens the address in a new tab.
Item values
valueitem-select with the item's value, its index, and its label, and an item with no value reports an empty string.
The item fires no choice event of its own. Listen on the menu for the choice.
Selected items
selected
The menu sets it on the item holding focus, and a sub-menu sets it on its anchor while open, so it cannot mark the current choice. Show the current choice with a leading check icon.
Keeping the menu open
A click or Enter on an item closes the menu. keep-open
Use it for an item that changes a setting the reader may want to change again, such as a view option.
Disabled items
disabled
A disabled item is not announced as disabled, so explain the state nearby, as the supporting text does here.
Sub-menus
A sub-menu is a child of a menu, or of another sub-menu. Its anchor slot holds the menu item that opens it, and every other child is one of its own items, a nested sub-menu, or a divider. Put a trailing arrow in the anchor item's end slot, and add flip-in-rtl so it mirrors in right-to-left layouts.
The anchor item stays highlighted while the sub-menu is open. Choosing an item closes every level, and the outermost menu fires item-select; the sub-menu fires none of the selection events.
Opening a sub-menu
A pointer opens a sub-menu after hover-open-delayhover-close-delay
Set hover-open-delay
Sub-menu density
density
What a sub-menu takes from its menu
A sub-menu never animates, always opens on hover and on a click of its anchor item, and always moves focus to its first item. Set the animation, the open action and the opening focus on the menu that holds it; the Overview's Sub-menus section lists what a sub-menu takes from its menu.
Names and states
A screen reader announces the menu with the menu role, after the WAI-ARIA Authoring Practices: Menu Button pattern. Each item is announced as a menuitem, or as a link when it has an hrefrole attribute on an item replaces menuitem.
- An item's accessible name is its
aria-label, or else the text in its default slot. Supporting text is not part of it, and an icon is hidden from assistive technology and never names the item. - An item takes only
aria-label,aria-selected,aria-checked,aria-expanded, andaria-haspopup. Any otheraria-*attribute has no effect. paints only, and is not announced as selected or checked. Setselectedaria-checkedand a matchingroleyourself to state a chosen value.- The menu writes no
aria-expanded,aria-haspopup, oraria-controlson its button. Setaria-haspopup="menu"yourself, and keeparia-expandedin step with thetoggleevent, whosenewStateis"open"or"closed". - A sub-menu's anchor item is announced as having a sub-menu, collapsed, and that state does not change when the sub-menu opens: update
aria-expandedon the item from the sub-menu'stoggleevent. The sub-menu has no label of its own; the anchor item names it. - Without a button in the
anchorslot, the menu shows a fallback icon button named by the English title "Open Menu", which is not localized. Supply your own button and name it. - A disabled item leaves the Tab order and typing a letter skips it, but it writes no
aria-disabled, so it is not announced as disabled. Say why it is unavailable near the menu. - A divider entry in
has the roleexpressContentseparator. - For extra content that is not a list of commands, use a popover. For a question the reader must answer, use a dialog.
Keyboard and focus
| Key | Action |
|---|---|
| Enter or Space on the button | Opens the menu with the button's own click |
| ArrowDown on the button | Opens the menu at the first item, or moves focus there when it is open |
| ArrowUp on the button | Opens the menu at the last item, or moves focus there when it is open |
| ArrowDown or ArrowUp in the menu | Moves focus to the next or previous item, wrapping at the ends and skipping disabled items |
| Home or End | Moves focus to the first or last item |
| A letter | Moves focus to the next item whose label starts with the letters typed |
| Enter or Space on an item | Chooses the item and closes the menu; a link item follows its link |
| ArrowRight on a sub-menu's anchor item | Opens the sub-menu at its first enabled item, as does Enter (ArrowLeft in right-to-left layouts) |
| ArrowLeft in a sub-menu | Closes it and returns focus to its anchor item, as does Escape; the parent menu stays open (ArrowRight in right-to-left layouts) |
| Escape | Closes the topmost open menu or popover, wherever focus is |
| Tab | Moves focus out of the menu, which closes it unless stay-open-on-focusout |
Enter and Space on the button are the button's own behavior. The menu adds the rest.
- Items draw a focus ring on keyboard focus, inside the item.
- On opening, focus goes where
says, and on closing it returns to the control that had it.default-focus turns the return off.skip-restore-focus stops the arrow keys at the first and last items.no-navigation-wrap on an item leaves the menu open after Enter, Space, or a click. Escape still closes it.keep-open- Activating a sub-menu's anchor item opens the sub-menu without choosing anything, and the parent menu stays open.
- The menu is not modal. The page behind it stays interactive, and a click outside closes it unless
is set.stay-open-on-outside-click - Typing letters is remembered for
milliseconds, 200 by default. Type-ahead matches an item's label; settypeahead-delaytypeahead-textto match other words.
Pointer and touch
A one-line item's container is 56 pixels high by default, above the 24 by 24 pixel minimum of WCAG 2.5.8 Target Size (Minimum). A denser density
- A pointer hovering over a sub-menu's anchor item opens it after
, and a tap opens it through the click. Hover is mouse-only, so a pointer leaving never closes what a tap opened.hover-open-delay
Display settings
- In forced-colors mode, the menu surface draws a 1 pixel border in
CanvasText, a disabled item is drawn inGrayText, and a selected item, such as an open sub-menu's anchor, gets a 3 pixel double border inCanvasText. - The menu does not respond to a reduced-motion preference. Set
toanimation for readers who need less motion. A sub-menu never animates.none - In right-to-left text, the keys that open and close a sub-menu swap sides, and the sub-menu opens toward the inline end. Nothing else mirrors by itself: add
flip-in-rtlto an arrow icon, or set orflip-leading-icon-in-rtl on an item.flip-trailing-icon-in-rtl
Standards
With its defaults, the menu meets four WCAG 2.2 success criteria:
- 2.1.1 Keyboard (A)
- 2.1.2 No Keyboard Trap (A)
- 2.5.2 Pointer Cancellation (A)
- 2.4.7 Focus Visible (AA)
Five more depend on how you use it:
- 1.1.1 Non-text Content (A): give a slotted image an alt, or mark a decorative one.
- 4.1.2 Name, Role, Value (A): give the button a name, set
aria-haspopup="menu"on it, keeparia-expandedin step on it and on each sub-menu's anchor item, and state a chosen value witharia-checkedand a matchingrole. - 2.5.3 Label in Name (A): keep an item's visible words in any
aria-labelyou give it. - 2.4.6 Headings and Labels (AA): write item labels that say what each command does, and label a sub-menu's anchor item with what the group holds.
- 2.5.8 Target Size (Minimum) (AA): measure each item at the density you choose, and keep it at least 24 by 24 pixels.