We'd like to set Google Analytics cookies to learn how people use the Knowledge Base, so we can improve it. We set them only if you accept.

Skip to main content
Digital Accessibility Knowledge Base

Menu

UI pattern

A menu offers actions or commands that users run on demand, in a popup or a persistent menubar. An accessible menu carries menu roles and accessible names, reports checked and expanded states, and keyboard users move through its items with the arrow keys.

Each item in a menu, such as "Copy" or "Paste," runs an action or command. A menu behaves like the menus in a desktop operating system: keyboard and screen reader users expect to open it, move between its items with the arrow keys, and activate an item to run its command.

A menu takes one of two forms. A popup menu, with role="menu", stays hidden until a user opens it, usually by activating a menu button or a menu item that opens a submenu.

A visible menu, with role="menubar", is a persistent bar of items, similar to the File, Edit, and View bar at the top of a desktop application. Either form can be hierarchical: an item in a menubar or a menu can open a submenu, which is itself a popup menu.

A menu isn't for choosing a value. A listbox, a combobox, or a native <select> element lets a user pick one or more values for later use, while activating a menu item performs its action right away. A menu also isn't site navigation, even though websites often call a set of navigation links a "menu." The ARIA menu roles promise desktop-style keyboard behavior that a list of links doesn't need.

When to Use

Use a menu when:

  • You're building an application-style set of commands, such as "Copy," "Paste," and "Delete," that users run on demand.
  • You want a persistent command bar, similar to the File, Edit, and View menubar in desktop software.
  • A command needs a submenu of related commands or options, such as a "Text size" submenu.
  • Users turn settings on and off in place, such as "Show preview," with checkable menu items.

Do not use a menu when:

  • The items are links to other pages. Use a navigation landmark with a list of links instead, as described in Site Navigation.
  • Users are choosing a value for later use, such as a country or a size. Use a listbox, a combobox, or a native <select> element.
  • The control only shows and hides a region of content. Use a disclosure.

Examples

Code in this section is meant to demonstrate techniques rather than requirements and lacks features needed in a production application.

HTML has no element that gives a menu its semantics and behavior. The <menu> element has the implicit role list and is equivalent to <ul>. A menu is built from generic HTML and <button> elements, with ARIA to describe it and JavaScript to manage focus. Both examples use a <button> for each item, so every item can take focus and responds to a click, while its role says what kind of menu item it is.

The menu is shown open. While it's closed, the menu carries the hidden attribute and the menu button has aria-expanded="false". The menu takes its accessible name from the button through aria-labelledby.

Every item has tabindex="-1", so none of them is in the tab order. When the menu opens, script moves focus to the first item, and the arrow keys move it from there. The <hr> elements have the implicit role separator. The <fieldset> has the implicit role group, named "Text size," and holds the two menuitemradio items.

Paste is unavailable until the clipboard has content, so it carries aria-disabled="true", which keeps it focusable. The disabled attribute would take it out of the arrow-key sequence.

Popup menu HTML
HTML
<button
  type="button"
  id="actions-button"
  aria-haspopup="menu"
  aria-expanded="true"
  aria-controls="actions-menu">
  Actions
</button>
<div
  id="actions-menu"
  role="menu"
  aria-labelledby="actions-button">
  <button
    type="button"
    role="menuitem"
    tabindex="-1">
    Copy
  </button>
  <button
    type="button"
    role="menuitem"
    tabindex="-1"
    aria-disabled="true">
    Paste
  </button>
  <hr />
  <button
    type="button"
    role="menuitemcheckbox"
    tabindex="-1"
    aria-checked="false">
    Show preview
  </button>
  <hr />
  <fieldset aria-label="Text size">
    <button
      type="button"
      role="menuitemradio"
      tabindex="-1"
      aria-checked="true">
      Small text
    </button>
    <button
      type="button"
      role="menuitemradio"
      tabindex="-1"
      aria-checked="false">
      Large text
    </button>
  </fieldset>
</div>

Menu Button covers the button's own requirements, and its Examples include a script that opens a menu like this one and moves focus through its items.

The menubar is one tab stop. The first item has tabindex="0" and the others have tabindex="-1". Script moves the tabindex="0" to whichever item the arrow keys move focus to, so Tab brings the user back to the item they last used. This is the roving tabindex technique. The <li> elements carry role="none" so the list semantics don't come between the menubar and its items.

Format and Align are parent menu items. Each declares its submenu with aria-haspopup="menu" and reports whether it's open with aria-expanded. Each submenu is the element immediately after its parent item and takes its accessible name from it through aria-labelledby. When a submenu opens, its parent item's aria-expanded changes to "true", the hidden attribute is removed, and focus moves to the submenu's first item.

Menubar with submenus HTML
HTML
<ul
  role="menubar"
  aria-label="Text editor">
  <li role="none">
    <button
      type="button"
      role="menuitem"
      id="format-item"
      aria-haspopup="menu"
      aria-expanded="false"
      tabindex="0">
      Format
    </button>
    <ul
      role="menu"
      aria-labelledby="format-item"
      hidden>
      <li role="none">
        <button
          type="button"
          role="menuitemcheckbox"
          aria-checked="true"
          tabindex="-1">
          Bold
        </button>
      </li>
      <li role="none">
        <button
          type="button"
          role="menuitemcheckbox"
          aria-checked="false"
          tabindex="-1">
          Italic
        </button>
      </li>
    </ul>
  </li>
  <li role="none">
    <button
      type="button"
      role="menuitem"
      id="align-item"
      aria-haspopup="menu"
      aria-expanded="false"
      tabindex="-1">
      Align
    </button>
    <ul
      role="menu"
      aria-labelledby="align-item"
      hidden>
      <li role="none">
        <button
          type="button"
          role="menuitemradio"
          aria-checked="true"
          tabindex="-1">
          Left
        </button>
      </li>
      <li role="none">
        <button
          type="button"
          role="menuitemradio"
          aria-checked="false"
          tabindex="-1">
          Center
        </button>
      </li>
      <li role="none">
        <button
          type="button"
          role="menuitemradio"
          aria-checked="false"
          tabindex="-1">
          Right
        </button>
      </li>
    </ul>
  </li>
  <li role="none">
    <button
      type="button"
      role="menuitem"
      tabindex="-1">
      Clear formatting
    </button>
  </li>
</ul>

Structure and Semantics

A menu is built from ARIA roles. The container carries menu or menubar, each item carries menuitem, menuitemcheckbox, or menuitemradio, and group and separator organize the items. Each item belongs to a menu or menubar, directly or through a group inside one. Elements that only structure the markup, such as the <li> elements of a list, carry role="none" so they don't come between a menu and its items.

Every interactive element inside a menu is a menu item. A plain button, link, or form control placed among the items has no place in the menu's structure, so assistive technology presents it inconsistently and the menu's focus management passes over it.

Role or attributeHow to use
role="menu"Set on the container of a popup menu or submenu. Its implicit aria-orientation is vertical.
role="menubar"Set on the container of a visible menu. Its implicit aria-orientation is horizontal.
role="menuitem"Set on each item that runs a command or opens a submenu.
role="menuitemcheckbox"Set on an item that turns an option on or off. Requires aria-checked.
role="menuitemradio"Set on each item of a set in which only one can be checked. Requires aria-checked.
role="group"Wraps a set of related items, such as a set of menuitemradio items, and takes an accessible name. A <fieldset> has this role implicitly.
role="separator"Divides groups of items. It isn't focusable and needs no name. An <hr> has this role implicitly.
aria-labelledby, aria-labelName the menu or menubar. Point aria-labelledby at visible text or at the control that opens the menu, and use aria-label when there's none.
aria-checkedSet to "true" or "false" on a menuitemcheckbox or menuitemradio, and update it when the item is operated.
aria-disabledSet to "true" on an item that's unavailable. The item stays focusable.
aria-haspopup, aria-expandedSet on a parent menu item that opens a submenu. aria-haspopup="menu" declares the submenu, and aria-expanded reports whether it's open.
aria-orientationSet only when the layout differs from the role's default, such as "vertical" on a menubar laid out as a column.
tabindex, aria-activedescendantManage focus inside the menu, either by moving tabindex="0" among the items or by pointing aria-activedescendant on the container at the focused item.

A menu or menubar contains at least one item with the role menuitem, menuitemcheckbox, or menuitemradio, either as a child or inside a group. Other roles, such as button, link, or option, don't count, however much the items look like menu items.

Gives members the required role

Reported as: No group members with required role

A menu or menubar must contain items with a menu item role.

When the container's children have no menu item role, such as <button> elements left with their native role, assistive technology reports a menu with nothing in it. Screen reader users can't move through or activate its items the way the menu promises.

Give each item role="menuitem", menuitemcheckbox, or menuitemradio, and place it directly in the menu or inside a group in the menu.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.

Role

Each part of a menu exposes the role its place in the menu calls for. A menu item carries menuitem, menuitemcheckbox, or menuitemradio on the element users focus and activate, which in the examples is the <button>, not the <li> around it.

Has the correct role

Reported as: Element has incorrect role

Each part of a menu must expose its role: menu or menubar on the container, and menuitem, menuitemcheckbox, or menuitemradio on each item.

When an item keeps its native role, such as a <button> without role="menuitem", or the container has no role, assistive technology presents a set of buttons or plain content rather than a menu. Users aren't told they can move through it with the arrow keys, and checkable items don't report their state.

Set role="menu" or role="menubar" on the container, and the matching menu item role on each item.

Severity: Critical

StandardSuccess CriterionReference
WCAG 2.24.1.2 Name, Role, Value (A)For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies.
EN 301 5499.4.1.2 Name, Role, ValueSame as the WCAG text.
Section 5081194.21(d)Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text.
Applies role to the correct element

Reported as: Incorrect root element

Sanity check. Evinced checks that each menu item role sits on the element users focus and activate, not on a wrapper around it. This check runs on every UI pattern, not only on menus.

A menu item role should sit on the element that users focus and activate.

When the role is on a wrapper, such as an <li role="menuitem"> around a focusable <button>, focus lands on an element that assistive technology reports as a plain button. The menu item itself never receives focus, so what users hear doesn't match the menu's structure.

Put the role, the accessible name, and the focus handling on the same element, and give any wrapper role="none".

Accessible Name

Each menu item has an accessible name that says what it does. The name usually comes from the item's text. An item that shows only an icon needs a name from aria-label or from visually hidden text.

The following example names an icon-only item with aria-label.

HTML
<button type="button" role="menuitem" tabindex="-1" aria-label="Delete file">
  <svg aria-hidden="true" focusable="false">...</svg>
</button>
Has an accessible name

Reported as: Accessible name

A menu item must have an accessible name that says what it does.

When an item has no name, as happens with an icon-only item, screen reader users hear only "menu item," and voice control users have nothing to say to activate it. Nobody using either can tell what the item does without running it.

Give each item visible text. When an item shows only an icon, add aria-label to the item and hide the icon with aria-hidden="true".

Severity: Critical

StandardSuccess CriterionReference
WCAG 2.24.1.2 Name, Role, Value (A)For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies.
EN 301 5499.4.1.2 Name, Role, ValueSame as the WCAG text.
Section 5081194.21(d)Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text.

A menu's items are named as a set: every item has a name, and no two items in the same menu share one. Users choose between items by their names, which they hear one at a time as they move through the menu.

Identifies each member by name

Reported as: Group members missing accessible names

Every item in a menu or menubar must have an accessible name.

When some items in a menu have no name, screen reader users moving through it hear "menu item" at those positions with nothing to tell the items apart. Voice control users can't activate them by name.

Give every item visible text, or an aria-label when it shows only an icon.

Severity: Critical

StandardSuccess CriterionReference
WCAG 2.24.1.2 Name, Role, Value (A)For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies.
EN 301 5499.4.1.2 Name, Role, ValueSame as the WCAG text.
Section 5081194.21(d)Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text.
Tells one member from another

Reported as: Group contains duplicate names

Items in the same menu should each have a different accessible name.

When two items share a name, such as two "Edit" items for different targets, screen reader users can't tell which does what, and voice control users can't choose between them.

Make each name distinct, for example "Edit document" and "Edit template." When only the context differs, fold that context into the name rather than relying on the item's position.

Severity: Serious

This issue is classified as "Best Practice," meaning it isn't tied to a specific WCAG success criterion or any other regulation or standard; however it still affects the experience of some users. These issues fall outside formal compliance requirements, yet addressing them improves usability and accessibility in practice.

Accessibility Label

A menu or menubar has an accessible name that says what its commands are for, such as "Actions" or "Text editor." A popup menu usually takes its name from the menu button or parent menu item that opens it, through aria-labelledby. A menubar points aria-labelledby at a visible heading, or uses aria-label when there isn't one. The Examples show both.

Names a container that needs one

Reported as: Missing contextual labeling

A menu or menubar must have an accessible name that identifies it.

When a menu has no name, assistive technology reports only that the user has entered a menu. Screen reader users aren't told which one, and on a page with several menus they can't tell them apart or decide whether to enter one without going through its items.

Give a popup menu aria-labelledby that points to the control that opens it. Point a menubar's aria-labelledby at its visible label, or use aria-label when there's no visible text. Name the menu for what it holds rather than with the word "menu."

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.

aria-haspopup

A parent menu item declares that it opens a submenu with aria-haspopup="menu", or "true", which means the same thing. Items that run a command don't carry it.

Has an aria-haspopup attribute

Reported as: Menu button has no aria-haspopup attribute

A parent menu item should carry aria-haspopup to declare its submenu.

When the attribute is missing, screen reader users aren't told that the item opens a submenu. They may activate it expecting a command, or not look for the options it holds.

Add aria-haspopup="menu" to each menu item that opens a submenu.

Severity: Moderate

This issue is classified as "Best Practice," meaning it isn't tied to a specific WCAG success criterion or any other regulation or standard; however it still affects the experience of some users. These issues fall outside formal compliance requirements, yet addressing them improves usability and accessibility in practice.
Sets correct aria-haspopup value

Reported as: Invalid aria-haspopup value

A parent menu item's aria-haspopup value should name the kind of popup it opens.

When the value names a different kind of popup, such as "dialog" or "listbox" on an item that opens a submenu, or isn't a value ARIA defines, assistive technology describes the wrong popup or none. Users can't anticipate what opening the item will do.

Set aria-haspopup to "menu" or "true", and give the submenu it opens role="menu".

Severity: Minor

This issue is classified as "Best Practice," meaning it isn't tied to a specific WCAG success criterion or any other regulation or standard; however it still affects the experience of some users. These issues fall outside formal compliance requirements, yet addressing them improves usability and accessibility in practice.

Keyboard Navigation Orientation

A menu moves focus with Up Arrow and Down Arrow, and a menubar with Left Arrow and Right Arrow, the orientations their roles imply. When a menu's layout differs, aria-orientation declares it, and the keys follow the declaration.

Declares the orientation it uses

Reported as: Conflicting aria-orientation

A menu's aria-orientation value must match the arrow keys that move focus through it.

When the declared orientation and the keys disagree, such as a menubar laid out as a column that keeps its implicit horizontal orientation while Up Arrow and Down Arrow move focus, screen readers tell users to press keys that don't work.

Set aria-orientation="vertical" on a vertical menubar or "horizontal" on a horizontal menu, and leave it out when the layout matches the role's default.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.22.1.1 Keyboard (A)All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints.
EN 301 5499.2.1.1 KeyboardSame as the WCAG text.
Section 5081194.21(a)When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually.
508 Trusted Tester2.1.1-keyboard-access, 4.AAll functionality can be accessed and executed using only the keyboard.
Uses a valid aria-orientation value

Reported as: Invalid aria-orientation value

A menu's aria-orientation should be "horizontal" or "vertical".

When the attribute holds any other value, such as a misspelling, assistive technology ignores it and uses the role's default. When that default doesn't match the layout, screen readers tell users to press keys that don't work.

Use one of the two values, or remove the attribute when the role's default is correct.

Severity: Minor

This issue is classified as "Best Practice," meaning it isn't tied to a specific WCAG success criterion or any other regulation or standard; however it still affects the experience of some users. These issues fall outside formal compliance requirements, yet addressing them improves usability and accessibility in practice.

aria-expanded

A parent menu item, one that opens a submenu, reports whether its submenu is open through aria-expanded: "false" while the submenu is hidden and "true" while it's shown. A menu button meets the same requirement for the menu it opens.

Reflects aria-expanded state

Reported as: Conflicting aria-expanded value

A parent menu item's aria-expanded value must match whether its submenu is visible.

When the value contradicts the screen, such as "false" while the submenu is displayed, screen reader users are told the opposite of what sighted users see. They may try to open a submenu that's already open, or not know that one is showing.

Set aria-expanded="true" whenever the submenu is shown and "false" whenever it's hidden, in the same function that shows and hides it.

Severity: Critical

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.
Updates aria-expanded

Reported as: Aria-expanded value did not change

A parent menu item's aria-expanded value must change every time its submenu opens or closes.

When the value is set once and never updated, it's right in only one state. Screen reader users hear the same state whether the submenu is open or closed, and get no confirmation that their action opened it.

Update aria-expanded each time the submenu opens or closes, whether a key press, a click, or a script opens or closes it.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.
Has aria-expanded

Reported as: Missing aria-expanded attribute

A parent menu item must carry an aria-expanded attribute.

When the attribute is missing, assistive technology can't report whether the submenu is open, so screen reader users don't know whether the options they're looking for are available.

Add aria-expanded="false" to every parent menu item, and change it to "true" while its submenu is shown. Leave it off items that run a command.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.

Disabled

A menu item that's unavailable reports that it's disabled and stays in the menu, where users can still reach it with the arrow keys. aria-disabled="true" does both, and script ignores any attempt to run the item. The disabled attribute doesn't suit a menu item, even one built on a <button>, because it removes the item from focus.

Disables only when role allows

Reported as: Component does not support disabled state

In a menu, only the menu or menubar, its groups, and its menu items, including items that open submenus, can declare a disabled state.

When disabled or aria-disabled sits on a separator, on a wrapper around an item, or on an icon inside one, assistive technology may drop the state or report it on something users can't operate, while the item itself is still reported as available.

Move the state onto each menu item that isn't available, or onto the menu or menubar when none of its items is.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.24.1.2 Name, Role, Value (A)For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies.
EN 301 5499.4.1.2 Name, Role, ValueSame as the WCAG text.
Section 5081194.21(d)Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text.
Disables only elements that support it

Reported as: Element type does not support disabled state

An element in a menu must carry disabled or aria-disabled only when its role supports a disabled state.

When the state sits on an element whose role has none, such as a wrapper, a list item or a heading, assistive technology may drop it or report it on something users can't operate, while the control that really is unavailable is still reported as available.

Remove the attribute from that element, and set the disabled state on the control itself, using an element or role that supports it, such as a native <button>.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.24.1.2 Name, Role, Value (A)For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies.
EN 301 5499.4.1.2 Name, Role, ValueSame as the WCAG text.
Section 5081194.21(d)Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text.
Avoids conflicting disabled states

Reported as: Conflicting disabled values

A menu item must declare its disabled state in one way, with one value.

When an item carries both disabled and aria-disabled with values that disagree, such as disabled with aria-disabled="false", assistive technology can report a state different from the one the browser enforces. Users can't tell whether the item will run.

Use aria-disabled alone on menu items, and remove it or set it to "false" when the item becomes available.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.24.1.2 Name, Role, Value (A)For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies.
EN 301 5499.4.1.2 Name, Role, ValueSame as the WCAG text.
Section 5081194.21(d)Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text.
Uses aria-disabled rather than disabled

Reported as: Element does not support the disabled attribute

A menu item must convey its disabled state with aria-disabled.

When a <div> or <li> used as a menu item carries the disabled attribute, the browser ignores it. Assistive technology reports the item as available, so screen reader users aren't told it's unavailable, and it still runs when anyone activates it.

Set aria-disabled="true" on the item, and have script ignore Enter, Space, and clicks on it until it's available again.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.24.1.2 Name, Role, Value (A)For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies.
EN 301 5499.4.1.2 Name, Role, ValueSame as the WCAG text.
Section 5081194.21(d)Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text.
Keeps disabled items findable

Reported as: Disabled menu item not discoverable

A disabled menu item must stay reachable with the arrow keys.

When arrow-key navigation skips disabled items, keyboard and screen reader users never learn those commands exist. They can't tell that an option is unavailable for now rather than missing.

Keep disabled items in the arrow-key sequence, and let aria-disabled="true" report their state. Ignore attempts to run them instead of removing them from navigation.

Severity: Minor

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.

A menu runs commands on the current page. The ARIA menu roles aren't for site navigation, even when the links sit in a dropdown that looks like a menu. Screen readers treat a menu as an application control, so a user expecting a list of links gets unfamiliar keys and loses the link behavior they rely on.

For the recommended way to build site navigation, refer to Site Navigation.

Uses links for moving between pages

Reported as: Misused role for site navigation

A control that takes users to another page must be a link, not a menu item.

When a menu or its items change the page's URL, assistive technology presents links as commands. Screen reader users have to operate them with the arrow keys instead of their usual link commands, and can't open a destination in a new tab or find it in a list of the page's links.

Build site navigation as a <nav> element containing a list of links, and use disclosure buttons to show and hide nested lists.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.24.1.2 Name, Role, Value (A)For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies.
EN 301 5499.4.1.2 Name, Role, ValueSame as the WCAG text.

A parent menu item that declares a submenu has one: an element with role="menu" placed immediately after it, inside the same menu.

The association also depends on the parent item's aria-expanded value tracking whether the submenu is shown.

Has an associated menu

Reported as: Menu button has no associated menu

A parent menu item that declares a submenu must have one, with role="menu".

When an item carries aria-haspopup but no submenu follows it, or the submenu has no menu role, screen reader users are told a submenu exists and can't reach it, or reach content that doesn't behave like a menu.

Place the submenu immediately after its parent item, give it role="menu", and name it from the parent item with aria-labelledby.

Severity: Critical

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.
Updates aria-expanded

Reported as: Aria-expanded value did not change

A parent menu item's aria-expanded value must change to "true" when its submenu appears and to "false" when it disappears.

When the submenu opens but the value stays "false", assistive technology reports a closed submenu that's on screen, so screen reader users don't know there are items to move into.

Update aria-expanded in the same code that shows and hides the submenu.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.
Has aria-expanded

Reported as: Missing aria-expanded attribute

A parent menu item must carry an aria-expanded attribute so the state of its submenu can be reported.

When the attribute is missing, assistive technology has no state to report, so screen reader users can't tell whether the submenu is open or closed.

Set aria-expanded="false" on the parent item when the page loads, and keep it in step with the submenu.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.
Sits beside its launcher

Reported as: Menu is not an immediate sibling of its launcher

A submenu should be the element immediately after its parent menu item in the DOM.

When other elements come between a parent item and its submenu, or the submenu sits elsewhere in the page, assistive technology may not associate the two. Screen reader users reading through the page no longer hear the submenu's items right after the item that opens them.

Move the submenu directly after its parent item, inside the same menu or menubar, as in the Menubar With Submenus example.

Severity: Minor

This issue is classified as "Best Practice," meaning it isn't tied to a specific WCAG success criterion or any other regulation or standard; however it still affects the experience of some users. These issues fall outside formal compliance requirements, yet addressing them improves usability and accessibility in practice.

Unexpected Interactives

A menu holds menu items: menuitem, menuitemcheckbox and menuitemradio, optionally in groups and with separators. Users move through them with the arrow keys and choose one, so a control of another kind doesn't fit how a menu is operated.

Holds only expected controls

Reported as: Unexpected interactives in menu

A menu must hold only interactive elements with a menu item role.

When a text field, a checkbox, a slider or another control sits among the items, the menu's arrow keys skip it, or users reach it without knowing how to operate it, and screen reader users hear a control the menu pattern doesn't expect.

Give each command a menu item role, using menuitemcheckbox or menuitemradio for a choice, and move any other control out of the menu, for example into a dialog the menu opens.

Severity: Minor

This issue is classified as "Best Practice," meaning it isn't tied to a specific WCAG success criterion or any other regulation or standard; however it still affects the experience of some users. These issues fall outside formal compliance requirements, yet addressing them improves usability and accessibility in practice.

Relationships

A popup menu and a menubar are two forms of the same pattern and hold their items the same way. Items belong to a menu by being inside it in the DOM, either as children or inside a group element. That gives assistive technology the menu's structure and gives users a reading order that matches the screen.

A parent menu item and the submenu it opens are related by position and by reference. The submenu is the element immediately after its parent item, inside the same menu, and takes its name from the parent item through aria-labelledby. A menu button relates to its menu in the same way.

aria-owns

A menu has no need for aria-owns when its items are nested inside it in the DOM, directly or inside a group. When items are rendered elsewhere, the first fix is to move them into the menu or portal the whole menu. Using aria-owns changes only the accessibility tree, so it comes last.

Avoids aria-owns

Reported as: Avoid aria-owns

General check. Evinced checks that a menu or menubar doesn't use aria-owns to claim items or submenus that aren't nested inside it. This check runs on every UI pattern, not only on menus.

A menu or menubar should hold its items in the DOM, directly or inside a group, in the order the arrow keys move through them, rather than claim them with aria-owns.

When items rendered elsewhere are owned, assistive technology that honors the attribute places them after the menu's own items, and assistive technology that doesn't reports them outside the menu. Screen reader users then hear the items in a different order from the one the arrow keys follow, or find items the menu doesn't count.

Render the items inside the menu, and when a framework portals a popup menu, portal the whole menu. Place each submenu immediately after its parent item, and when the parent item references it, use aria-controls rather than aria-owns.

Owns only conforming roles

Reported as: Invalid aria-owns values

General check. Evinced checks that every element a menu or menubar references in aria-owns has a role the menu can contain. This check runs on several UI patterns.

When a menu uses aria-owns, each element it references should have the menuitem, menuitemcheckbox, menuitemradio, group, or separator role, and a group should reference only menu items.

When an owned element has another role, such as a plain button or a listitem, the menu's structure no longer adds up. The item count and positions come out wrong, and the arrow keys can reach an element the menu doesn't handle. An element owned by two containers, or two containers that own each other, leaves the structure undefined.

Reference only elements with those roles, and own each element from one container.

Operation

With a pointer, users click or tap a menu button or a parent menu item to open its menu, and click or tap an item to run it, which usually closes the menu. Clicking outside an open menu closes it without running anything.

With a keyboard, a menu is one stop in the tab order. Tab moves focus to the menubar, or to the control that opens a popup menu. From inside a menu, Tab moves focus out of it and closes any open menus. Inside the menu, the keys in the following table move focus and run items.

The table describes a horizontal menubar with vertical submenus. When a menu's orientation differs, the arrow keys swap roles to match.

KeyFunction
Right Arrow, Left ArrowIn a menubar, moves focus to the next or previous item. In a submenu, Right Arrow opens the focused item's submenu, and Left Arrow closes the current submenu and returns focus to its parent item.
Down Arrow, Up ArrowIn a menu, moves focus to the next or previous item, optionally wrapping at the ends. On a parent item in a menubar, Down Arrow opens its submenu and moves focus to the first item, and Up Arrow (optional) opens it and moves focus to the last item.
EnterOn a parent item, opens its submenu and moves focus to the first item. On any other item, runs it and closes the menu.
SpaceToggles a menuitemcheckbox, or checks a menuitemradio, without closing the menu. On other items, optionally acts like Enter.
Home, EndMoves focus to the first or last item.
EscapeCloses the menu that contains focus and returns focus to the element that opened it.
Printable character (optional)Moves focus to the next item whose name begins with that character.

A custom menu has to provide all of this in script. Handle the keys on keydown, which fires for every key, rather than the deprecated keypress event. Focus moves among the items either by the roving tabindex technique or with aria-activedescendant, as described in Keyboard Navigation Inside Components.

Focus Sequence

A menubar is one stop in the tab order. When focus arrives, it lands on the first item, or on the item that last had focus, and the arrow keys take it from there. A popup menu isn't in the tab order. Users reach it through the control that opens it, and focus moves into it when it opens.

Reachable with the Tab key

Reported as: Composite not in focus sequence

One item of a menubar must be in the tab order.

When every item has tabindex="-1", or the items are elements that can't take focus, keyboard users can't reach the menubar, so none of its commands are available to them.

Give the first item tabindex="0" and the others tabindex="-1". Alternatively, make the menubar container focusable and indicate the focused item with aria-activedescendant.

Severity: Critical

StandardSuccess CriterionReference
WCAG 2.22.1.1 Keyboard (A)All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints.
EN 301 5499.2.1.1 KeyboardSame as the WCAG text.
Section 5081194.21(a)When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually.
508 Trusted Tester2.1.1-keyboard-access, 4.AAll functionality can be accessed and executed using only the keyboard.
Lands on the selected item

Reported as: Composite unpredictable focus

When focus enters a menubar, it must land on the first item, or on the item that last had focus.

When Tab puts focus somewhere else, such as on a middle item or on the menubar container with no item focused, keyboard users start from an unexpected place. Screen reader users don't hear the item they expect, or hear no item at all.

Keep tabindex="0" on the first item until the user moves, and then on the item they last focused. When using aria-activedescendant, set it to that item as the menubar receives focus.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.22.1.1 Keyboard (A)All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints.
EN 301 5499.2.1.1 KeyboardSame as the WCAG text.
Section 5081194.21(a)When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually.
508 Trusted Tester2.1.1-keyboard-access, 4.AAll functionality can be accessed and executed using only the keyboard.
Gives its items a single tab stop

Reported as: Redundant focusable children

A menubar must have only one item in the tab order.

When every item has tabindex="0", or native focusable elements keep their default focus behavior, Tab stops at every item. Keyboard users have to press Tab through the whole menubar to get past it, and nothing tells them to use the arrow keys instead.

Set tabindex="-1" on every item except the one that holds the tab stop, and move tabindex="0" as focus moves.

Severity: Moderate

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.

Focus Management

Opening a submenu from the keyboard moves focus into it, onto its first item, and closing it with Escape returns focus to the parent item that opened it. A popup menu opened by a menu button behaves the same way.

Moves focus on open

Reported as: Focus on menu open

Opening a submenu from the keyboard must move focus into it.

When focus stays on the parent item after the submenu opens, keyboard users see options they can't reach with the keys they expect, and screen reader users aren't told the submenu has opened.

When Enter, Space, or an arrow key opens the submenu, move focus into it.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.22.1.1 Keyboard (A)All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints.
EN 301 5499.2.1.1 KeyboardSame as the WCAG text.
Section 5081194.21(a)When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually.
508 Trusted Tester2.1.1-keyboard-access, 4.AAll functionality can be accessed and executed using only the keyboard.
Restores focus on Escape

Reported as: Focus on menu close

Closing a submenu with Escape must return focus to the parent item that opened it.

When focus goes somewhere else, such as to the top of the page, keyboard users lose their place in the menu and have to find their way back to it. Screen reader users may not know the submenu has closed.

On Escape, hide the submenu, set the parent item's aria-expanded to "false", and move focus to the parent item.

Severity: Moderate

StandardSuccess CriterionReference
WCAG 2.22.1.1 Keyboard (A)All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints.
EN 301 5499.2.1.1 KeyboardSame as the WCAG text.
Section 5081194.21(a)When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually.
508 Trusted Tester2.1.1-keyboard-access, 4.AAll functionality can be accessed and executed using only the keyboard.
Focuses menu item on open

Reported as: Invalid focus position on menu open

Opening a submenu from the keyboard must put focus on its first item.

When focus lands on a later item, or on the submenu container with no item focused, users start partway through the options and may miss the items above. Screen reader users hear an item without knowing where it sits in the list.

Focus the first item each time a submenu opens. The one exception is Up Arrow opening a submenu from a menubar, which focuses the last item.

Severity: Moderate

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.

Keyboard Navigation

The arrow keys move focus from item to item in a menu or menubar, in the direction the items are laid out, and disabled items stay in the sequence. The following example handles the arrow keys, Home, and End on keydown for a vertical menu that uses a roving tabindex. Its list of items includes disabled items, so they stay reachable.

JavaScript
menu.addEventListener("keydown", (event) => {
  const items = Array.from(menu.querySelectorAll('[role^="menuitem"]'));
  const index = items.indexOf(document.activeElement);
  if (index === -1) return;


  let next;
  switch (event.key) {
    case "ArrowDown":
      next = items[(index + 1) % items.length];
      break;
    case "ArrowUp":
      next = items[(index - 1 + items.length) % items.length];
      break;
    case "Home":
      next = items[0];
      break;
    case "End":
      next = items[items.length - 1];
      break;
    default:
      return;
  }


  event.preventDefault();
  items[index].tabIndex = -1;
  next.tabIndex = 0;
  next.focus();
});
Moves focus to the expected item

Reported as: Menu unexpected focus shift

Each arrow key press in a menu must move focus to the adjacent item in that direction.

When an arrow key skips items, jumps to an unrelated element, or sends focus to the top of the page, keyboard users lose their place, and screen reader users can't form a picture of the menu.

Move focus to the next or previous item on each press, in the order the items appear, and keep focus inside the menu until Tab or Escape takes it out.

Severity: Critical

StandardSuccess CriterionReference
WCAG 2.22.1.1 Keyboard (A)All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints.
EN 301 5499.2.1.1 KeyboardSame as the WCAG text.
Section 5081194.21(a)When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually.
508 Trusted Tester2.1.1-keyboard-access, 4.AAll functionality can be accessed and executed using only the keyboard.
Keeps disabled items findable

Reported as: Disabled menu item not discoverable

A disabled menu item must stay reachable with the arrow keys that move through its menu.

When the arrow keys pass over disabled items, keyboard and screen reader users never land on them, so they don't learn that those commands exist but are unavailable for now.

Include disabled items in the set the arrow keys move through, mark them with aria-disabled="true", and ignore attempts to run them.

Severity: Minor

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.
Matches arrow keys to orientation

Reported as: Arrow key navigation failed

Sanity check. Evinced checks that the arrow keys matching a menu's orientation move focus from item to item. This check runs on several UI patterns.

A menu should move focus with the arrow keys that match its layout.

When the arrow keys don't move focus, or only the keys for the other direction do, keyboard users can't reach the items past the one that has focus.

Handle Up Arrow and Down Arrow in a vertical menu, and Left Arrow and Right Arrow in a horizontal menubar, on keydown on the menu container.

Keyboard Activation

A parent menu item opens its submenu from the keyboard with Enter, Space, or the arrow key that points into the submenu, and its aria-expanded value changes as it does.

Updates aria-expanded

Reported as: Aria-expanded value did not change

A parent menu item must update its aria-expanded value when the keyboard opens or closes its submenu.

When the submenu opens on Enter or an arrow key but aria-expanded stays "false", screen reader users aren't told their key press opened anything, and hear a closed state for a submenu they're now inside.

Set aria-expanded in the same function that shows and hides the submenu, so key presses, clicks, and Escape all update it.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.
Has aria-expanded

Reported as: Missing aria-expanded attribute

A parent menu item must carry an aria-expanded attribute, so opening its submenu from the keyboard has a state to update.

When the attribute is missing, screen reader users who press Enter, Space, or an arrow key get no confirmation that the submenu opened, or that it closed again.

Add aria-expanded="false" to the parent item, and set it to "true" when the keyboard opens the submenu.

Severity: Serious

StandardSuccess CriterionReference
WCAG 2.21.3.1 Info and Relationships (A)Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
EN 301 5499.1.3.1 Info and RelationshipsSame as the WCAG text.

Checked Menu Items

A menuitemcheckbox or menuitemradio reports whether it's checked with aria-checked, and the value changes when the item is operated. Space changes it without closing the menu, so users can set several options in one visit. Checking one menuitemradio unchecks the others in its group.

Toggles a checkable menu item

Reported as: Menuitemcheckbox Not Toggled

A checkable menu item must change its aria-checked value when it's operated, and Space must do so without closing the menu.

When Space leaves the value unchanged, or closes the menu without toggling the item, keyboard users can't set the option. Screen reader users get no confirmation that anything happened.

Handle Space on each checkable item: toggle aria-checked on a menuitemcheckbox, or check a menuitemradio and uncheck the others in its group, and keep the menu open.

Severity: Critical

StandardSuccess CriterionReference
WCAG 2.22.1.1 Keyboard (A)All functionality of the content is operable through a keyboard interface without requiring specific timings for individual keystrokes, except where the underlying function requires input that depends on the path of the user's movement and not just the endpoints.
EN 301 5499.2.1.1 KeyboardSame as the WCAG text.
Section 5081194.21(a)When software is designed to run on a system that has a keyboard, product functions shall be executable from a keyboard where the function itself or the result of performing a function can be discerned textually.
508 Trusted Tester2.1.1-keyboard-access, 4.AAll functionality can be accessed and executed using only the keyboard.
Reports a checkable item state

Reported as: Menuitemcheckbox has no aria-checked attribute

A menuitemcheckbox or menuitemradio must carry aria-checked.

When the attribute is missing, assistive technology can't report whether the option is on, so screen reader users don't know the current setting before they change it.

Set aria-checked="true" or "false" on every checkable item from the start, and keep it in step with the setting.

Severity: Critical

StandardSuccess CriterionReference
WCAG 2.24.1.2 Name, Role, Value (A)For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies.
EN 301 5499.4.1.2 Name, Role, ValueSame as the WCAG text.
Section 5081194.21(d)Sufficient information about a user interface element including the identity, operation and state of the element shall be available to assistive technology. When an image represents a program element, the information conveyed by the image must also be available in text.

Event Listener Type

When script in a menu responds to keys, it listens for keydown or keyup. The keypress event is deprecated, and browsers don't fire it for many keys, including the arrow keys, Home, End and Escape.

Avoids the keypress event

Reported as: Deprecated keypress listener

A menu's key handling should use keydown or keyup, not keypress.

When a handler listens for keypress, keys the browser doesn't send through that event go unanswered, and keyboard users find the menu ignoring keys it's meant to respond to.

Replace each keypress listener with a keydown listener, and read the key from event.key.

Severity: Minor

This issue is classified as "Best Practice," meaning it isn't tied to a specific WCAG success criterion or any other regulation or standard; however it still affects the experience of some users. These issues fall outside formal compliance requirements, yet addressing them improves usability and accessibility in practice.

FAQ

Which WCAG success criteria do the menu issues relate to?

Under 4.1.2 Name, Role, Value, a menu and its items carry their roles, each item has an accessible name, the disabled state is declared correctly, checkable items carry aria-checked, and site navigation uses links rather than menu items.

Under 1.3.1 Info and Relationships, a menu contains menu items and has a name of its own, parent items report their submenus with aria-expanded, each submenu is associated with its parent item, disabled items stay reachable, a menubar has a single tab stop, and opening a submenu focuses its first item.

Under 2.1.1 Keyboard, aria-orientation matches the arrow keys, a menubar is reachable with Tab and focus lands on its first item, focus moves into a submenu and returns on Escape, the arrow keys move focus between items, and Space toggles checkable items. Distinct item names, a valid aria-haspopup and aria-orientation, and a submenu placed right after its parent item map to no WCAG success criterion and are best practices.

Why are some menu issues marked as Critical and others as Minor?

Severity reflects how much an issue gets in users' way. Critical issues stop users outright:

  • A menu or menu item without its role, or a menu item without a name
  • An aria-expanded value that contradicts the screen
  • A parent menu item with no submenu
  • A menubar keyboard users can't reach
  • Arrow keys that move focus to the wrong place
  • A checkable menu item that doesn't toggle or report its state

Serious issues mislead or strand users:

  • A menu with no menu items, or with no name of its own
  • Menu items that share a name
  • An aria-orientation value that contradicts the arrow keys
  • A missing or unchanging aria-expanded value
  • A wrong disabled state
  • Menu roles used for site navigation
  • Focus that lands away from the first menu item, or doesn't move into a submenu that opens

Moderate issues weaken orientation:

  • A missing aria-haspopup
  • Every menu item in the tab order
  • Focus that isn't restored on Escape, or lands on the wrong item when a submenu opens

Minor issues break a convention without blocking the task:

  • An aria-haspopup or aria-orientation value that doesn't fit
  • A disabled menu item the arrow keys skip
  • A submenu placed away from its parent item

Four checks carry no severity: the two general checks on aria-owns, and the sanity checks on where the menu item role sits and on arrow-key navigation.

  • Menu Button: a button that opens a popup menu
  • Listbox: a list of values users choose from, rather than commands they run
  • Combobox: an input that opens a list of values to select
  • Site Navigation: navigation links that open in a popup without menu roles
  • Disclosure: a button that shows and hides content rather than opening a menu