Skip to content
Ndop UI

Menu primitive

Headless Menu: the behavior, keyboard support and ARIA of the WAI-ARIA Menu pattern, with no styles.

Import

Primitives ship in the @ndop/primitives package and have no styles. Their state is on data attributes for you to style.

import {
  NdMenuContent,
  NdMenuGroup,
  NdMenuItemCheckbox,
  NdMenuItemIndicator,
  NdMenuLabel,
  NdMenuRadioGroup,
  NdMenuSeparator,
  NdMenuItem,
  NdMenuItemRadio,
  NdMenuSubTrigger,
} from '@ndop/primitives/menu';

Accessibility

Implements the Menu pattern of the WAI-ARIA Authoring Practices.

Keyboard

Keys the component handles.

Key Action
ArrowDownorArrowUpMoves focus to the next or previous item, wrapping.
HomeorEndMoves focus to the first or last item.
EnterActivates the focused item and closes the menu.
SpaceActivates the focused item; checkbox and radio items keep the menu open.
ArrowRightOn a sub-trigger, opens its menu and focuses the first item.
ArrowLeftIn a submenu, closes it and focuses its sub-trigger.
EscapeCloses the current menu and returns focus to what opened it.
TabCloses every open menu and moves focus on from the trigger.
aTypeahead: moves focus to the next item whose label starts with the typed letters.

Focus

  • Opened from the keyboard, a menu focuses its first item (its last with ArrowUp on a Dropdown Menu trigger); opened with the pointer, the menu itself.
  • Closing returns focus to the trigger or sub-trigger.

Right-to-left

ArrowLeft opens submenus and ArrowRight closes them, and submenus open on the left. Direction comes from the app's Directionality: the document's dir, or a CDK [dir] directive.

API reference

NdMenuContent

[ndMenuContent]role menufrom @ndop/primitives/menu

A menu: a list of actions in a role="menu" element, composing the CDK's CdkMenu (ADR-0004, amendment 3). Put it in an ng-template that a Dropdown Menu trigger, a Context Menu trigger or a ndMenuSubTrigger renders. Arrow keys, Home, End and typeahead move between items; Escape closes it and returns focus to what opened it.

Manages aria-orientation.

NdMenuContent binding Type Default
(closed)
Emits when the menu closes.
void—
Data attribute Values
data-stateopen
data-side —

NdMenuGroup

[ndMenuGroup]role groupfrom @ndop/primitives/menu

Groups related items (role="group"). Name it with aria-labelledby pointing at a ndMenuLabel.

NdMenuItemCheckbox

[ndMenuItemCheckbox]role menuitemcheckboxfrom @ndop/primitives/menu

A menu item that is on or off (role="menuitemcheckbox"), composing CdkMenuItemCheckbox. Activating it flips checked; Space keeps the menu open.

Manages aria-checked, aria-disabled.

NdMenuItemCheckbox binding Type Default
[disabled]
Makes it inert but focusable, with aria-disabled.
booleanfalse
[(checked)]
Whether it's on. Two-way bindable with [(checked)].
booleanfalse
(triggered)
Emits when it's activated.
void—
Data attribute Values
data-state —
data-disabled —

NdMenuItemIndicator

[ndMenuItemIndicator]from @ndop/primitives/menu

The check or dot of a checkbox or radio item. It has the hidden attribute while its item is unchecked.

Data attribute Values
data-state —

NdMenuLabel

[ndMenuLabel]from @ndop/primitives/menu

A heading for a group of items, as plain text; point the group's aria-labelledby at it.

NdMenuRadioGroup

[ndMenuRadioGroup]role groupfrom @ndop/primitives/menu

Groups radio items (role="group") and holds which one is checked. Name it with aria-labelledby pointing at a ndMenuLabel.

NdMenuRadioGroup binding Type Default
[(value)]
The checked radio item's value, or null. Two-way bindable with [(value)].
string | nullnull

NdMenuSeparator

[ndMenuSeparator]role separatorfrom @ndop/primitives/menu

A line between groups of items (role="separator").

NdMenuItem

[ndMenuItem]role menuitemfrom @ndop/primitives/menu

One action in a menu (role="menuitem"), composing CdkMenuItem. Activating it with a click, Enter or Space emits triggered and closes every open menu. disabled sets aria-disabled only, never the native attribute: disabled items stay focusable and do nothing. Use a div, as on a button browsers turn Space into a click, which closes the menu.

Manages aria-disabled.

NdMenuItem binding Type Default
[disabled]
Makes it inert but focusable, with aria-disabled.
booleanfalse
(triggered)
Emits when it's activated.
void—
Data attribute Values
data-disabled —

NdMenuItemRadio

[ndMenuItemRadio]role menuitemradiofrom @ndop/primitives/menu

One choice in a NdMenuRadioGroup (role="menuitemradio"), composing CdkMenuItemRadio. Activating it makes its value the group's; Space keeps the menu open.

Manages aria-checked, aria-disabled.

NdMenuItemRadio binding Type Default
[value]required
The value its group takes when it's checked.
string—
[disabled]
Makes it inert but focusable, with aria-disabled.
booleanfalse
(triggered)
Emits when it's activated.
void—
Data attribute Values
data-state —
data-disabled —

NdMenuSubTrigger

[ndMenuSubTrigger]role menuitemfrom @ndop/primitives/menu

A menu item that opens the submenu in the ng-template it's given (role="menuitem" with aria-haspopup="menu"): with a click, hover, Enter, Space or the arrow key toward the end side.

Manages aria-haspopup, aria-expanded, aria-controls.

NdMenuSubTrigger binding Type Default
[ndMenuSubTrigger]
The ng-template of the submenu.
TemplateRef<unknown> | nullnull
[disabled]
Makes it inert but focusable, with aria-disabled.
booleanfalse
Data attribute Values
data-state —
data-disabled —