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.

Cancel Cancel order Keep order Copy Copy link Copy text Edit Cut Copy Paste Order Reorder last Track parcel Cancel order Undo Undo typing Redo Next Skip Snooze Share Email Copy link Messages Updates Mark all read Notification settings Join Join with video Join with audio only Inbox Compose Refresh Download PDF CSV Plain text Pay Card Bank transfer Start New project Open recent Import Back Back Forward Reload Details Properties Activity Reply Reply all Forward More Archive Move to Mute Checkout Pay now Save for later Add to cart Add one Add as a gift Add to wishlist Buy Buy now Buy later Preview Page Slide Full screen Skip Skip once Skip always Archive Archive Archive all Continue Continue Continue later Paste Paste Paste plain text Save Save Save as Done Done Done and next Clear Clear all Clear filters Retry Retry now Retry later

Reference docs⁠

BlazorReactWebOverviewExamplesAPIStylingAccessibility

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 no-navigation-wrap stops the wrap at either end.
  • Type-ahead finds an item by its label, and typeahead-delay sets the pause that resets it.
  • Arrow keys on the button open the menu at its first or last item.
  • A choice closes the menu and reports the item's value, index, and label in item-select; keep-open on an item leaves the menu open.
  • Closing returns focus to where it was before the menu opened, unless skip-restore-focus is set.
  • Items come from child elements or from data, with expressContent.
  • An item's start and end slots take any icon, avatar, or control, and leading-icon-name and trailing-icon-name draw an icon with no markup. Overline, supporting text, and trailing supporting text give a row up to four kinds of text.
  • href makes an item a link, and disabled keeps it on screen and out of the keyboard's way.
  • A sub-menu opens on hover after hover-open-delay (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.

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, and change.
  • Set on the sub-menu itself: the two hover delays, hover-open-delay and hover-close-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.
  • 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⁠

animation sets how the menu appears and disappears. Omit it and the menu takes the animation from your style configuration, which is faded-slide unless you have changed it.

Choose expand when the menu should grow out of its button, and none when it should appear at once.

Default focus⁠

default-focus sets where keyboard focus lands when the menu opens. The default is first-item, so a keyboard user who opens the menu is already on the first command.

Choose last-item for a menu whose likeliest command sits at the bottom. With none, focus stays on the button, which suits a menu opened from a text field that keeps the typing focus.

Density⁠

density sets how tightly the items sit, from 0, the standard spacing, to 4, the tightest. Omit it and the menu takes its density from your style configuration, which is the standard spacing unless you have changed it.

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-action sets what opens the menu. A click is the default, click. With hover-focus, pointing at the button or focusing it opens the menu after hover-open-delay, and leaving closes it after hover-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 items, and its label.

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 turns the wrap off, which suits a menu that follows a pattern with no wrap, such as a combobox.

Type-ahead matches the letters you type against item labels. typeahead-delay is the longest pause between two letters before the typed text is forgotten, 200 milliseconds by default.

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-click stops a click elsewhere on the page from closing the menu. stay-open-on-focusout does the same when focus leaves, and skip-restore-focus leaves focus where it is after closing. Turn on the one the reader's task needs, since a menu that never closes by itself is easy to strand open.

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 anchor to that control's id and set external-anchor to say that no slotted anchor opens it. The menu then positions itself against that control.

anchorElement takes the element itself instead, and is the only way to anchor to a button that sits inside another component, since an id cannot reach it. Set it from script; markup has no attribute for it.

Items from data⁠

expressContent renders the items from an array instead of child elements. Each entry is a string, or an object for an item with an icon, supporting text, or a sub-menu.

Use one source of items, children or data. Choose data when the commands come from a list your code already holds.

Opening from code⁠

open opens and closes the menu from code, and show() 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-name and trailing-icon-name take a Material Symbols name and draw it in the start 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-rtl or flip-trailing-icon-in-rtl, which mirror it in right-to-left text. Add flip-in-rtl to an icon in a slot for the same effect.

href turns the item into a link. Choosing it follows the link and closes the menu, like any other choice. target sets where the link opens. Unset, it opens in the same tab.

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⁠

value is what the menu reports about the choice. The outermost menu fires item-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 paints the item in the selected container color. It is a visual state only: it is not announced as selected or checked, and it chooses nothing.

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 stops that: the click does nothing to the menu and the item reports no choice. Escape still closes it.

Use it for an item that changes a setting the reader may want to change again, such as a view option.

Disabled items⁠

disabled makes the item unchoosable. It stays on screen; keyboard navigation passes over it, and a click does nothing.

A disabled item is not announced as disabled, so explain the state nearby, as the supporting text does here.

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.

A pointer opens a sub-menu after hover-open-delay and closes it hover-close-delay after the pointer leaves the anchor item and the sub-menu. Both are in milliseconds and default to 400. A click or tap on the anchor item opens it at once without choosing anything, and a sub-menu nested in another opens with no delay.

Set hover-open-delay to 0 for a sub-menu that opens the moment the pointer arrives. The first sub-menu below waits for the default delay, and the second opens immediately.

density sets how tightly the sub-menu packs its items, from 0 for standard spacing to 4 for the densest. Omit it and the sub-menu takes its density from your style configuration, which is standard unless you have changed it. Set it on the sub-menu itself.

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.

Menu Menu item Sub menu
PropertyAttributeTypeDescription
SlotDescription
anchorThe element that opens the menu when activated, typically a cw-button or cw-icon-button.
(default)A series of cw-menu-item and cw-sub-menu elements to be shown in the menu.
EventTypeDetailDescription
beforetoggleToggleEvent—Fired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
toggleToggleEvent—Fired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
changeSelectionChangeEventSelectionChangeEventDetail<TItem>Fired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting value from code does not fire it. It bubbles.
inputInputEvent—Fired when the reader chooses an item, before change. It bubbles and is composed.
item-selectItemSelectEventItemSelectEventDetail<TItem>Fired by the outermost menu when the user selects an item, carrying the item's value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed.

On a choice, input fires first, then change, then item-select, and the menu closes after all three.

MethodReturnsDescription
hide()voidCloses it, as setting open to false does.
show()voidOpens it, as setting open to true does.
PropTypeDescription
ChildDescription
a child with slot="anchor"The element that opens the menu when activated, typically a CrButton or CrIconButton.
childrenA series of CrMenuItem and CrSubMenu elements to be shown in the menu.
PropArgumentDescription
onBeforeToggleToggleEventFired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
onToggleToggleEventFired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
onChangeSelectionChangeEvent<TItem>Fired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting value from code does not fire it. It bubbles. Its detail carries value and values.
onInputReact.ChangeEvent<HTMLInputElement>Fired when the reader chooses an item, before change. It bubbles and is composed.
onItemSelectItemSelectEvent<TItem>Fired by the outermost menu when the user selects an item, carrying the item's value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed. Its detail carries value, index, and label.

On a choice, input fires first, then change, then item-select, and the menu closes after all three.

Call these on the element the ref holds.

MethodReturnsDescription
hide()voidCloses it, as setting open to false does.
show()voidOpens it, as setting open to true does.
ParameterTypeDescription

Once you write AnchorContent or any other fragment as a child element, the main content must go in an explicit <ChildContent> too; markup beside <AnchorContent> is a compile error. Here ChildContent is: A series of CbMenuItem and CbSubMenu elements to be shown in the menu.

<CbMenu>
    <AnchorContent><CbButton>Open</CbButton></AnchorContent>
    <ChildContent>Main content</ChildContent>
</CbMenu>
content_copy
ParameterTypeDescription
AnchorContentRenderFragment?The element that opens the menu when activated, typically a CbButton or CbIconButton.
ChildContentRenderFragment?A series of CbMenuItem and CbSubMenu elements to be shown in the menu.
ParameterTypeDescription
OnBeforeToggleEventCallback<ToggleEventArgs>Fired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
OnToggleEventCallback<ToggleEventArgs>Fired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
OnChangeEventCallback<SelectionChangeEventArgs<TItem>>Fired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting Value from code does not fire it. It bubbles. Its detail carries Value and values.
OnInputEventCallback<ChangeEventArgs>Fired when the reader chooses an item, before change. It bubbles and is composed.
OnItemSelectEventCallback<ItemSelectEventArgs<TItem>>Fired by the outermost menu when the user selects an item, carrying the item's Value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed. Its detail carries Value, index, and label.

On a choice, input fires first, then change, then item-select, and the menu closes after all three.

InputTypeDescription
ContentDescription
an element with slot="anchor"The element that opens the menu when activated, typically a CaButton or CaIconButton.
content with no slotA series of CaMenuItem and CaSubMenu elements to be shown in the menu.
OutputEventDescription
cwBeforeToggleToggleEventFired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
cwToggleToggleEventFired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
cwChangeSelectionChangeEventFired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting value from code does not fire it. It bubbles. Its detail carries value and values.
cwInputInputEventFired when the reader chooses an item, before change. It bubbles and is composed.
cwItemSelectItemSelectEventFired by the outermost menu when the user selects an item, carrying the item's value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed. Its detail carries value, index, and label.

On a choice, input fires first, then change, then item-select, and the menu closes after all three.

Call these on the element the ref holds.

MethodReturnsDescription
hide()voidCloses it, as setting open to false does.
show()voidOpens it, as setting open to true does.
PropTypeDescription
SlotDescription
defaultA series of CvMenuItem and CvSubMenu elements to be shown in the menu.
anchorThe element that opens the menu when activated, typically a CvButton or CvIconButton.
EventTypeDescription
beforeToggleToggleEventFired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
toggleToggleEventFired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
changeSelectionChangeEventFired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting value from code does not fire it. It bubbles. Its detail carries value and values.
inputInputEventFired when the reader chooses an item, before change. It bubbles and is composed.
itemSelectItemSelectEventFired by the outermost menu when the user selects an item, carrying the item's value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed. Its detail carries value, index, and label.

On a choice, input fires first, then change, then item-select, and the menu closes after all three.

Call these on the element the ref holds.

MethodReturnsDescription
hide()voidCloses it, as setting open to false does.
show()voidOpens it, as setting open to true does.
PropTypeDescription
SnippetDescription
anchorSnippetThe element that opens the menu when activated, typically a CsButton or CsIconButton.
childrenA series of CsMenuItem and CsSubMenu elements to be shown in the menu.
PropTypeDescription
onBeforeToggleToggleEventFired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
onToggleToggleEventFired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
onChangeSelectionChangeEventFired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting value from code does not fire it. It bubbles. Its detail carries value and values.
onInputInputEventFired when the reader chooses an item, before change. It bubbles and is composed.
onItemSelectItemSelectEventFired by the outermost menu when the user selects an item, carrying the item's value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed. Its detail carries value, index, and label.

On a choice, input fires first, then change, then item-select, and the menu closes after all three.

Call these on the element the ref holds.

MethodReturnsDescription
hide()voidCloses it, as setting open to false does.
show()voidOpens it, as setting open to true does.
PropertyAttributeTypeDescription
SlotDescription
containerContent shown behind the item, such as a background image.
overlineA small text snippet above the headline.
(default)The headline/custom content.
supporting-textSupporting text lines underneath the headline.
startAny leading content, such as icons, avatars, or checkboxes.
endAny trailing content, such as icons and buttons.
trailing-supporting-textA small text snippet at the end of the item.
EventTypeDetailDescription
link-activateLinkActivateEventLinkActivateEventDetailFired when the link is followed in the same tab, before the browser navigates. Cancel it to navigate with a router instead. It bubbles, is composed, and is cancelable.
clickMouseEvent—Dispatched when the item is clicked. It bubbles, is composed, and is cancelable.
PropTypeDescription
ChildDescription
a child with slot="container"Content shown behind the item, such as a background image.
a child with slot="overline"A small text snippet above the headline.
childrenThe headline/custom content.
a child with slot="supporting-text"Supporting text lines underneath the headline.
a child with slot="start"Any leading content, such as icons, avatars, or checkboxes.
a child with slot="end"Any trailing content, such as icons and buttons.
a child with slot="trailing-supporting-text"A small text snippet at the end of the item.
PropArgumentDescription
onLinkActivateLinkActivateEventFired when the link is followed in the same tab, before the browser navigates. Cancel it to navigate with a router instead. It bubbles, is composed, and is cancelable. Its detail carries href, target, download, rel, altKey, ctrlKey, metaKey, shiftKey, and originalEvent.
onClickReact.MouseEvent<HTMLElement>Dispatched when the item is clicked. It bubbles, is composed, and is cancelable.
ParameterTypeDescription

Once you write Container or any other fragment as a child element, the main content must go in an explicit <ChildContent> too; markup beside <Container> is a compile error. Here ChildContent is: The headline/custom content.

<CbMenuItem>
    <Container>Content</Container>
    <ChildContent>Main content</ChildContent>
</CbMenuItem>
content_copy
ParameterTypeDescription
ChildContentRenderFragment?The headline/custom content.
ContainerRenderFragment?Content shown behind the item, such as a background image.
EndRenderFragment?Any trailing content, such as icons and buttons.
OverlineRenderFragment?A small text snippet above the headline.
StartRenderFragment?Any leading content, such as icons, avatars, or checkboxes.
SupportingTextRenderFragment?Supporting text lines underneath the headline.
TrailingSupportingTextRenderFragment?A small text snippet at the end of the item.
ParameterTypeDescription
OnLinkActivateEventCallback<LinkActivateEventArgs>Fired when the link is followed in the same tab, before the browser navigates. Cancel it to navigate with a router instead. It bubbles, is composed, and is cancelable. Its detail carries Href, Target, Download, Rel, altKey, ctrlKey, metaKey, shiftKey, and originalEvent.
OnClickEventCallback<MouseEventArgs>Dispatched when the item is clicked. It bubbles, is composed, and is cancelable.
InputTypeDescription
ContentDescription
an element with slot="container"Content shown behind the item, such as a background image.
an element with slot="overline"A small text snippet above the headline.
content with no slotThe headline/custom content.
an element with slot="supporting-text"Supporting text lines underneath the headline.
an element with slot="start"Any leading content, such as icons, avatars, or checkboxes.
an element with slot="end"Any trailing content, such as icons and buttons.
an element with slot="trailing-supporting-text"A small text snippet at the end of the item.
OutputEventDescription
cwLinkActivateLinkActivateEventFired when the link is followed in the same tab, before the browser navigates. Cancel it to navigate with a router instead. It bubbles, is composed, and is cancelable. Its detail carries href, target, download, rel, altKey, ctrlKey, metaKey, shiftKey, and originalEvent.
cwClickMouseEventDispatched when the item is clicked. It bubbles, is composed, and is cancelable.
PropTypeDescription
SlotDescription
defaultThe headline/custom content.
containerContent shown behind the item, such as a background image.
endAny trailing content, such as icons and buttons.
overlineA small text snippet above the headline.
startAny leading content, such as icons, avatars, or checkboxes.
supporting-textSupporting text lines underneath the headline.
trailing-supporting-textA small text snippet at the end of the item.
EventTypeDescription
linkActivateLinkActivateEventFired when the link is followed in the same tab, before the browser navigates. Cancel it to navigate with a router instead. It bubbles, is composed, and is cancelable. Its detail carries href, target, download, rel, altKey, ctrlKey, metaKey, shiftKey, and originalEvent.
clickMouseEventDispatched when the item is clicked. It bubbles, is composed, and is cancelable.
PropTypeDescription
SnippetDescription
containerSnippetContent shown behind the item, such as a background image.
overlineSnippetA small text snippet above the headline.
childrenThe headline/custom content.
supportingTextSnippetSupporting text lines underneath the headline.
startSnippetAny leading content, such as icons, avatars, or checkboxes.
endSnippetAny trailing content, such as icons and buttons.
trailingSupportingTextSnippetA small text snippet at the end of the item.
PropTypeDescription
onLinkActivateLinkActivateEventFired when the link is followed in the same tab, before the browser navigates. Cancel it to navigate with a router instead. It bubbles, is composed, and is cancelable. Its detail carries href, target, download, rel, altKey, ctrlKey, metaKey, shiftKey, and originalEvent.
onClickMouseEventDispatched when the item is clicked. It bubbles, is composed, and is cancelable.
PropertyAttributeTypeDescription
SlotDescription
anchorThe cw-menu-item that opens the sub menu when hovered or clicked.
(default)The sub menu's content: cw-menu-item elements, nested cw-sub-menu elements and dividers.
EventTypeDetailDescription
beforetoggleToggleEvent—Fired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
toggleToggleEvent—Fired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
changeSelectionChangeEventSelectionChangeEventDetail<TItem>Fired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting value from code does not fire it. It bubbles.
inputInputEvent—Fired when the reader chooses an item, before change. It bubbles and is composed.
item-selectItemSelectEventItemSelectEventDetail<TItem>Fired by the outermost menu when the user selects an item, carrying the item's value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed.

A sub-menu fires none of input, change, or item-select. The outermost menu fires them when an item at any level is chosen.

MethodReturnsDescription
hide()voidCloses the submenu.
show()voidShows the submenu.

show() opens the sub-menu from code and highlights its anchor; hide() closes it again.

PropTypeDescription
ChildDescription
a child with slot="anchor"The CrMenuItem that opens the sub menu when hovered or clicked.
childrenThe sub menu's content: CrMenuItem elements, nested CrSubMenu elements and dividers.
PropArgumentDescription
onBeforeToggleToggleEventFired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
onToggleToggleEventFired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
onChangeSelectionChangeEvent<TItem>Fired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting value from code does not fire it. It bubbles. Its detail carries value and values.
onInputReact.ChangeEvent<HTMLInputElement>Fired when the reader chooses an item, before change. It bubbles and is composed.
onItemSelectItemSelectEvent<TItem>Fired by the outermost menu when the user selects an item, carrying the item's value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed. Its detail carries value, index, and label.

A sub-menu fires none of input, change, or item-select. The outermost menu fires them when an item at any level is chosen.

Call these on the element the ref holds.

MethodReturnsDescription
hide()voidCloses the submenu.
show()voidShows the submenu.

show() opens the sub-menu from code and highlights its anchor; hide() closes it again.

ParameterTypeDescription

Once you write AnchorContent or any other fragment as a child element, the main content must go in an explicit <ChildContent> too; markup beside <AnchorContent> is a compile error. Here ChildContent is: The sub menu's content: CbMenuItem elements, nested CbSubMenu elements and dividers.

<CbSubMenu>
    <AnchorContent><CbButton>Open</CbButton></AnchorContent>
    <ChildContent>Main content</ChildContent>
</CbSubMenu>
content_copy
ParameterTypeDescription
AnchorContentRenderFragment?The CbMenuItem that opens the sub menu when hovered or clicked.
ChildContentRenderFragment?The sub menu's content: CbMenuItem elements, nested CbSubMenu elements and dividers.
ParameterTypeDescription
OnBeforeToggleEventCallback<ToggleEventArgs>Fired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
OnToggleEventCallback<ToggleEventArgs>Fired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
OnChangeEventCallback<SelectionChangeEventArgs<TItem>>Fired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting Value from code does not fire it. It bubbles. Its detail carries Value and values.
OnInputEventCallback<ChangeEventArgs>Fired when the reader chooses an item, before change. It bubbles and is composed.
OnItemSelectEventCallback<ItemSelectEventArgs<TItem>>Fired by the outermost menu when the user selects an item, carrying the item's Value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed. Its detail carries Value, index, and label.

A sub-menu fires none of input, change, or item-select. The outermost menu fires them when an item at any level is chosen.

InputTypeDescription
ContentDescription
an element with slot="anchor"The CaMenuItem that opens the sub menu when hovered or clicked.
content with no slotThe sub menu's content: CaMenuItem elements, nested CaSubMenu elements and dividers.
OutputEventDescription
cwBeforeToggleToggleEventFired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
cwToggleToggleEventFired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
cwChangeSelectionChangeEventFired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting value from code does not fire it. It bubbles. Its detail carries value and values.
cwInputInputEventFired when the reader chooses an item, before change. It bubbles and is composed.
cwItemSelectItemSelectEventFired by the outermost menu when the user selects an item, carrying the item's value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed. Its detail carries value, index, and label.

A sub-menu fires none of input, change, or item-select. The outermost menu fires them when an item at any level is chosen.

PropTypeDescription
SlotDescription
defaultThe sub menu's content: CvMenuItem elements, nested CvSubMenu elements and dividers.
anchorThe CvMenuItem that opens the sub menu when hovered or clicked.
EventTypeDescription
beforeToggleToggleEventFired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
toggleToggleEventFired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
changeSelectionChangeEventFired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting value from code does not fire it. It bubbles. Its detail carries value and values.
inputInputEventFired when the reader chooses an item, before change. It bubbles and is composed.
itemSelectItemSelectEventFired by the outermost menu when the user selects an item, carrying the item's value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed. Its detail carries value, index, and label.

A sub-menu fires none of input, change, or item-select. The outermost menu fires them when an item at any level is chosen.

PropTypeDescription
SnippetDescription
anchorSnippetThe CsMenuItem that opens the sub menu when hovered or clicked.
childrenThe sub menu's content: CsMenuItem elements, nested CsSubMenu elements and dividers.
PropTypeDescription
onBeforeToggleToggleEventFired before the opening or closing animation begins. Cancelable: calling preventDefault() leaves the menu as it is. newState is "open" or "closed". It bubbles, is composed, and is cancelable.
onToggleToggleEventFired once the menu has opened or closed, after any animations. newState is "open" or "closed". It bubbles and is composed.
onChangeSelectionChangeEventFired by the outermost menu when the reader chooses an item, its own or one inside a sub-menu, carrying the chosen value in detail.value (and detail.values). Setting value from code does not fire it. It bubbles. Its detail carries value and values.
onInputInputEventFired when the reader chooses an item, before change. It bubbles and is composed.
onItemSelectItemSelectEventFired by the outermost menu when the user selects an item, carrying the item's value, its index within the items of the menu or sub-menu that holds it, and its label. A sub-menu does not fire it. Additive to the native input/change events. It bubbles and is composed. Its detail carries value, index, and label.

A sub-menu fires none of input, change, or item-select. The outermost menu fires them when an item at any level is chosen.

Menu Menu item Sub menu

A value is what the token defaults to; selecting it copies the token's name.

TokenValue
--ct-menu-container-color--ct-sys-color-surface-container --ct-menu-container-color
--ct-menu-container-elevation--ct-sys-elevation-level2 --ct-menu-container-elevation
--ct-menu-container-shadow-color--ct-sys-color-shadow --ct-menu-container-shadow-color
--ct-menu-divider-bottom-space12px --ct-menu-divider-bottom-space
--ct-menu-divider-top-space12px --ct-menu-divider-top-space
--ct-menu-outline-colortransparent --ct-menu-outline-color
--ct-menu-outline-opacity1 --ct-menu-outline-opacity
--ct-menu-outline-width0px --ct-menu-outline-width
--ct-menu-position-areablock-end span-inline-end --ct-menu-position-area
--ct-menu-scrollbar-color--ct-sys-color-on-surface-variant --ct-menu-scrollbar-color
--ct-menu-scrollbar-widththin --ct-menu-scrollbar-width

A value is what the token defaults to; selecting it copies the token's name.

TokenValue
--ct-menu-item-bottom-space12px --ct-menu-item-bottom-space
--ct-menu-item-container-colortransparent --ct-menu-item-container-color
--ct-menu-item-disabled-opacity0.38 --ct-menu-item-disabled-opacity
--ct-menu-item-hover-state-layer-color--ct-sys-color-on-surface --ct-menu-item-hover-state-layer-color
--ct-menu-item-hover-state-layer-opacity--ct-sys-state-hover-state-layer-opacity --ct-menu-item-hover-state-layer-opacity
--ct-menu-item-label-text-color--ct-sys-color-on-surface --ct-menu-item-label-text-color
--ct-menu-item-label-text-font--ct-sys-typescale-body-large-font --ct-menu-item-label-text-font
--ct-menu-item-label-text-line-height--ct-sys-typescale-body-large-line-height --ct-menu-item-label-text-line-height
--ct-menu-item-label-text-size--ct-sys-typescale-body-large-size --ct-menu-item-label-text-size
--ct-menu-item-label-text-tracking--ct-sys-typescale-body-large-tracking --ct-menu-item-label-text-tracking
--ct-menu-item-label-text-weight--ct-sys-typescale-body-large-weight --ct-menu-item-label-text-weight
--ct-menu-item-leading-icon-color--ct-sys-color-on-surface-variant --ct-menu-item-leading-icon-color
--ct-menu-item-leading-icon-size24px --ct-menu-item-leading-icon-size
--ct-menu-item-leading-space16px --ct-menu-item-leading-space
--ct-menu-item-one-line-container-height56px --ct-menu-item-one-line-container-height
--ct-menu-item-overline-color--ct-sys-color-on-surface-variant --ct-menu-item-overline-color
--ct-menu-item-overline-font--ct-sys-typescale-label-small-font --ct-menu-item-overline-font
--ct-menu-item-overline-line-height--ct-sys-typescale-label-small-line-height --ct-menu-item-overline-line-height
--ct-menu-item-overline-size--ct-sys-typescale-label-small-size --ct-menu-item-overline-size
--ct-menu-item-overline-tracking--ct-sys-typescale-label-small-tracking --ct-menu-item-overline-tracking
--ct-menu-item-overline-weight--ct-sys-typescale-label-small-weight --ct-menu-item-overline-weight
--ct-menu-item-pressed-state-layer-color--ct-sys-color-on-surface --ct-menu-item-pressed-state-layer-color
--ct-menu-item-pressed-state-layer-opacity--ct-sys-state-pressed-state-layer-opacity --ct-menu-item-pressed-state-layer-opacity
--ct-menu-item-selected-container-color--ct-sys-color-secondary-container --ct-menu-item-selected-container-color
--ct-menu-item-selected-label-text-color--ct-sys-color-on-secondary-container --ct-menu-item-selected-label-text-color
--ct-menu-item-supporting-text-color--ct-sys-color-on-surface-variant --ct-menu-item-supporting-text-color
--ct-menu-item-supporting-text-font--ct-sys-typescale-body-medium-font --ct-menu-item-supporting-text-font
--ct-menu-item-supporting-text-line-height--ct-sys-typescale-body-medium-line-height --ct-menu-item-supporting-text-line-height
--ct-menu-item-supporting-text-size--ct-sys-typescale-body-medium-size --ct-menu-item-supporting-text-size
--ct-menu-item-supporting-text-tracking--ct-sys-typescale-body-medium-tracking --ct-menu-item-supporting-text-tracking
--ct-menu-item-supporting-text-weight--ct-sys-typescale-body-medium-weight --ct-menu-item-supporting-text-weight
--ct-menu-item-top-space12px --ct-menu-item-top-space
--ct-menu-item-trailing-icon-color--ct-sys-color-on-surface-variant --ct-menu-item-trailing-icon-color
--ct-menu-item-trailing-icon-size24px --ct-menu-item-trailing-icon-size
--ct-menu-item-trailing-space16px --ct-menu-item-trailing-space
--ct-menu-item-trailing-supporting-text-color--ct-sys-color-on-surface-variant --ct-menu-item-trailing-supporting-text-color
--ct-menu-item-trailing-supporting-text-font--ct-sys-typescale-label-small-font --ct-menu-item-trailing-supporting-text-font
--ct-menu-item-trailing-supporting-text-line-height--ct-sys-typescale-label-small-line-height --ct-menu-item-trailing-supporting-text-line-height
--ct-menu-item-trailing-supporting-text-size--ct-sys-typescale-label-small-size --ct-menu-item-trailing-supporting-text-size
--ct-menu-item-trailing-supporting-text-tracking--ct-sys-typescale-label-small-tracking --ct-menu-item-trailing-supporting-text-tracking
--ct-menu-item-trailing-supporting-text-weight--ct-sys-typescale-label-small-weight --ct-menu-item-trailing-supporting-text-weight

A value is what the token defaults to; selecting it copies the token's name.

TokenValue
--ct-menu-container-color--ct-sys-color-surface-container --ct-menu-container-color
--ct-menu-container-elevation--ct-sys-elevation-level2 --ct-menu-container-elevation
--ct-menu-container-shadow-color--ct-sys-color-shadow --ct-menu-container-shadow-color
--ct-menu-divider-bottom-space12px --ct-menu-divider-bottom-space
--ct-menu-divider-top-space12px --ct-menu-divider-top-space
--ct-menu-outline-colortransparent --ct-menu-outline-color
--ct-menu-outline-opacity1 --ct-menu-outline-opacity
--ct-menu-outline-width0px --ct-menu-outline-width
--ct-menu-position-areablock-end span-inline-end --ct-menu-position-area
--ct-menu-scrollbar-color--ct-sys-color-on-surface-variant --ct-menu-scrollbar-color
--ct-menu-scrollbar-widththin --ct-menu-scrollbar-width
--ct-menu-sub-menu-position-areaspan-block-end inline-end --ct-menu-sub-menu-position-area

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 href; a role 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, and aria-haspopup. Any other aria-* attribute has no effect.
  • selected paints only, and is not announced as selected or checked. Set aria-checked and a matching role yourself to state a chosen value.
  • The menu writes no aria-expanded, aria-haspopup, or aria-controls on its button. Set aria-haspopup="menu" yourself, and keep aria-expanded in step with the toggle event, whose newState is "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-expanded on the item from the sub-menu's toggle event. The sub-menu has no label of its own; the anchor item names it.
  • Without a button in the anchor slot, 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 expressContent has the role separator.
  • 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 is set

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 default-focus says, and on closing it returns to the control that had it. skip-restore-focus turns the return off.
  • no-navigation-wrap stops the arrow keys at the first and last items.
  • keep-open on an item leaves the menu open after Enter, Space, or a click. Escape still closes it.
  • 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 stay-open-on-outside-click is set.
  • Typing letters is remembered for typeahead-delay milliseconds, 200 by default. Type-ahead matches an item's label; set typeahead-text to 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 setting reduces the spacing, so measure items at the density you choose, as the Density example shows. The button that opens the menu sets its own target size.

  • A pointer hovering over a sub-menu's anchor item opens it after hover-open-delay, and a tap opens it through the click. Hover is mouse-only, so a pointer leaving never closes what a tap opened.

Display settings⁠

  • In forced-colors mode, the menu surface draws a 1 pixel border in CanvasText, a disabled item is drawn in GrayText, and a selected item, such as an open sub-menu's anchor, gets a 3 pixel double border in CanvasText.
  • The menu does not respond to a reduced-motion preference. Set animation to none for readers who need less motion. A sub-menu never animates.
  • 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-rtl to an arrow icon, or set flip-leading-icon-in-rtl or flip-trailing-icon-in-rtl on an item.

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, keep aria-expanded in step on it and on each sub-menu's anchor item, and state a chosen value with aria-checked and a matching role.
  • 2.5.3 Label in Name (A): keep an item's visible words in any aria-label you 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.