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 Button

UI pattern

A menu button opens a menu of actions or options. An accessible menu button is an accessible button with aria-haspopup="menu", a name that identifies its menu, and aria-expanded to report its open state, and it moves focus into the menu.

A menu button is a specialized button that, when activated, displays a menu of options or actions, generally in an overlay (a "popup"). It builds on a generic button, adding the behavior needed to control its menu and ARIA attributes that inform assistive technologies of its properties and state:

  • The property attribute aria-haspopup with a value of either menu or true tells assistive technologies that the button opens a menu and that the menu is a composite widget that may be navigated with arrow keys.
  • The state attribute aria-expanded has a value of true or false to indicate whether the menu is displayed.

A menu button's accessibility requirements expand on those of a generic button, which are described in the Button entry.

The term "menu" also has a more exacting meaning here than is common. An accessible menu button does not open a list of navigation links. It opens a menu that contains a list of menu items that can be invoked to perform an action or function. Refer to the Menu entry for its accessibility requirements and the Site Navigation entry to learn about accessible navigation.

A disclosure button also carries aria-expanded, but it can control the display of any kind of content and says nothing about how that content is operated. Other buttons that display content have semantics of their own. Related Patterns lists their entries.

When to Use

Use a menu button when:

  • You want to group a set of related commands or actions in a menu that is shown on demand rather than always on screen.
  • You need to collect secondary commands behind a single control, such as a "More actions..." button.

Don't use a menu button when:

  • The popup or dropdown would contain navigation links. Activating a link inside a perceived menu could cause an unexpected change of context. Use a disclosure button instead. Refer to the Site Navigation entry to see how that works.
  • The control simply shows and hides a region of content. Use a disclosure instead.
  • The control opens a list of values for users to select. Use a combobox that opens a listbox instead.

Examples

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

An accessible menu button builds on a base button, adding ARIA attributes that convey its role, state, and relationship to the menu, and JavaScript to provide the necessary behavior. You can use either a native HTML <button> element or a custom button as the base. A custom button also needs script for its keyboard behavior, as described in Button › Examples.

In this example, a menu button controls a menu of file actions.

Menu button HTML
HTML
<button
  id="file-actions"
  aria-controls="file-menu"
  aria-expanded="false"
  aria-haspopup="menu"
>
  File Actions
</button>
<div
  id="file-menu"
  role="menu"
  aria-labelledby="file-actions"
>
  <button role="menuitem">New Document</button>
  <button role="menuitem">Save</button>
  <button role="menuitem">Print</button>
</div>

The menu button needs JavaScript for keyboard operation. This example manages keyboard focus using aria-activedescendant. When the menu button is activated, keyboard focus programmatically moves to the menu and stays there until the menu closes, and then returns to the menu button. The menu items themselves never receive keyboard focus.

For brevity, the following omits some details and error-condition checks. A custom button would need additional handlers.

Menu button JavaScript
JavaScript
class ActiveDescendantMenuButton {
  constructor(button) {
    this.button = button;


    const menuId = button.getAttribute("aria-controls");
    this.menu = document.getElementById(menuId);


    // Disabled items stay in the list, so the arrow keys still reach them.
    this.items = Array.from(this.menu.querySelectorAll('[role="menuitem"]'));


    this.activeIndex = -1;
    this.isOpen = false;


    this.initialize();
    this.addEventListeners();
  }


  initialize() {
    this.button.setAttribute("aria-haspopup", "menu");
    this.button.setAttribute("aria-expanded", "false");


    this.menu.setAttribute("role", "menu");
    this.menu.setAttribute("tabindex", "-1");
    this.menu.hidden = true;


    this.items.forEach((item, index) => {
      if (!item.id) {
        item.id = `${this.menu.id}-item-${index + 1}`;
      }
      // Individual items are not Tab stops in this focus model.
      item.tabIndex = -1;
    });
  }


  addEventListeners() {
    this.button.addEventListener("click", () => {
      if (this.isOpen) {
        this.close({ restoreFocus: true });
      } else {
        this.open({ focus: "first" });
      }
    });


    this.button.addEventListener("keydown", (event) => {
      this.onButtonKeydown(event);
    });


    this.menu.addEventListener("keydown", (event) => {
      this.onMenuKeydown(event);
    });


    // capture the click before it reaches the item's own handler
    this.menu.addEventListener(
      "click",
      (event) => {
        this.onMenuClick(event);
      },
      true
    );
  }


  // show the menu and set aria-expanded and focus
  open({ focus = "first" } = {}) {
    if (this.isOpen) {
      return;
    }


    this.isOpen = true;
    this.menu.hidden = false;
    this.button.setAttribute("aria-expanded", "true");


    if (focus === "last") {
      this.setActiveItem(this.items.length - 1);
    } else if (typeof focus === "number") {
      this.setActiveItem(focus);
    } else {
      this.setActiveItem(0);
    }


    this.menu.focus();
  }


  // hide the menu, reset aria-expanded and menu-button focus
  close({ restoreFocus = false } = {}) {
    if (!this.isOpen) {
      return;
    }


    this.isOpen = false;
    this.menu.hidden = true;
    this.menu.removeAttribute("aria-activedescendant");
    this.button.setAttribute("aria-expanded", "false");
    this.activeIndex = -1;


    if (restoreFocus) {
      this.button.focus();
    }
  }


  // set aria-activedescendant
  setActiveItem(index) {
    const itemCount = this.items.length;


    if (itemCount === 0) {
      return;
    }


    const normalizedIndex = ((index % itemCount) + itemCount) % itemCount;
    const previousItem = this.items[this.activeIndex];
    const nextItem = this.items[normalizedIndex];


    if (previousItem) {
      previousItem.classList.remove("is-active");
    }


    this.activeIndex = normalizedIndex;
    nextItem.classList.add("is-active");


    this.menu.setAttribute("aria-activedescendant", nextItem.id);


    nextItem.scrollIntoView({
      block: "nearest",
      inline: "nearest"
    });
  }


  // click the menu item to make it happen
  activateCurrentItem() {
    const activeItem = this.items[this.activeIndex];


    if (!activeItem || activeItem.getAttribute("aria-disabled") === "true") {
      return;
    }


    activeItem.click();
  }


  // What happens when focus is on the menu button
  onButtonKeydown(event) {
    switch (event.key) {
      case "Enter":
      case " ":
      case "ArrowDown":
        event.preventDefault();
        this.open({ focus: "first" });
        break;


      case "ArrowUp":
        event.preventDefault();
        this.open({ focus: "last" });
        break;


      case "Escape":
        if (this.isOpen) {
          event.preventDefault();
          this.close({ restoreFocus: true });
        }
        break;
    }
  }


  // What happens when focus is on the menu
  onMenuKeydown(event) {
    switch (event.key) {
      case "ArrowDown":
        event.preventDefault();
        this.setActiveItem(this.activeIndex + 1);
        break;


      case "ArrowUp":
        event.preventDefault();
        this.setActiveItem(this.activeIndex - 1);
        break;


      case "Home":
        event.preventDefault();
        this.setActiveItem(0);
        break;


      case "End":
        event.preventDefault();
        this.setActiveItem(this.items.length - 1);
        break;


      case "Enter":
      case " ":
        event.preventDefault();
        this.activateCurrentItem();
        break;


      case "Escape":
        event.preventDefault();
        this.close({ restoreFocus: true });
        break;


      case "Tab":
        // Let normal keyboard navigation proceed, but close the popup.
        this.close({ restoreFocus: false });
        break;
    }
  }


  // a click on a menu item, from a pointer or from activateCurrentItem(),
  // goes on to the item's own handler, and the menu closes
  onMenuClick(event) {
    const item = event.target.closest('[role="menuitem"]');


    if (!item || !this.menu.contains(item)) {
      return;
    }


    // a disabled item stops the click before it runs and leaves the menu open
    if (item.getAttribute("aria-disabled") === "true") {
      event.stopPropagation();
      event.preventDefault();
      return;
    }


    this.close({ restoreFocus: true });
  }
}


const fileActionMenuButton = new ActiveDescendantMenuButton(
  document.getElementById("file-actions")
);

Structure and Semantics

All users need to identify a menu button, understand its relationship to the menu it controls, and perceive its open and closed states. Semantic HTML and ARIA attributes convey these semantics to assistive technologies. A menu button either implicitly or explicitly carries the button role, has an accessible name that describes its menu, and adds the ARIA attributes aria-haspopup, aria-expanded, and aria-controls.

AttributeHow to use
aria-haspopupSet to menu (or true) on the button to tell assistive technologies that the button opens a menu in a popup that can be navigated with arrow keys.
aria-expandedSet to true while the menu is open and false while it's closed, so assistive technologies can report the button's state.
aria-controlsSet to the id of the menu the button opens.

The menu a menu button opens carries the menu role and 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 button's menu must contain items with a menu item role.

When the menu'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 open the menu and can't move through or run its items the way the button promised.

Give each item role="menuitem", menuitemcheckbox, or menuitemradio, as the example's items do, 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

A menu button exposes the button role so that assistive technologies can convey its purpose and how to interact with it. Use the native <button> element or an element with role="button".

Has the correct role

Reported as: Element has incorrect role

A menu button must carry the button role.

When the role is missing, or the element exposes a different role, screen reader users aren't told it's a button, so they don't know they can activate it to open its menu.

Use a <button> element, which carries the role implicitly, or set role="button" on the element that opens the menu.

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 the button role sits on the menu button itself, the element users focus and operate, rather than on one of its descendants. This check runs on every UI pattern, not only on menu buttons.

A menu button's button role should sit on the same element that receives focus, opens the menu, and carries aria-haspopup and aria-expanded.

When the role sits on a descendant while a wrapper takes focus or handles the click, assistive technology reports an element with no role and no expanded state, so screen reader users aren't told they've reached a menu button or whether its menu is open.

Put the role, the accessible name, aria-haspopup, aria-expanded, the tab stop, and the activation handling on one element, and keep any wrapper free of roles and handlers. If the test selected a wrapper by mistake, select the menu button itself and run the test again.

Button Name

A menu button has an accessible name that identifies the menu it opens. The name should describe the menu's purpose or content, such as "File", "Edit", or "Settings", rather than a generic name like "Menu" or "Button".

Has an accessible name

Reported as: Accessible name

A menu button must have an accessible name that identifies the menu it opens.

Without a name, screen reader users hear only "button" and can't tell what the menu offers or tell one menu button from another. Voice control users have no name to speak to open it.

Give the button visible text naming its menu, such as "File" or "Settings". When the button shows only an icon, give it an aria-label that names the menu.

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.

The items of a menu button's menu are named as a set: every item has a name, and no two items in the 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 button's menu must have an accessible name.

When some items have no name, screen reader users moving through the menu hear "menu item" at those positions with nothing to tell the items apart. Voice control users can't run 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 a menu button's menu should each have a different accessible name.

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

Make each name distinct, for example "Export as PDF" and "Export as Word". 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

The menu a menu button opens has an accessible name that says what its commands are for. It usually takes that name from the button, through aria-labelledby, as the example's menu does, so users hear the same name on the button and in the menu.

Names a container that needs one

Reported as: Missing contextual labeling

A menu button's menu must have an accessible name that identifies it.

When the 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 menu buttons they can't confirm they opened the menu they meant to.

Set aria-labelledby on the menu to the id of the menu button. Use aria-label only when there's no visible text to point at, and 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 menu button should declare aria-haspopup so assistive technologies can report that it opens a menu in a popup, and the value should identify that popup as a menu.

Has an aria-haspopup attribute

Reported as: Menu button has no aria-haspopup attribute

A menu button should carry an aria-haspopup attribute to indicate that it opens a menu.

When the button has no aria-haspopup attribute, screen reader users aren't told a popup menu is available before they activate it, so the menu comes as a surprise. Set aria-haspopup="menu" on the button (or true, which means the same thing).

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 menu button should set the aria-haspopup attribute to a value that correctly describes the type of popup it opens.

When aria-haspopup is set to a value that doesn't describe a menu, screen readers may announce the wrong kind of popup, or none, so users can't anticipate what activating the button will do. Set aria-haspopup to menu (or true, which means the same thing), and make sure the popup it opens has 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.
Matches aria-haspopup to its popup

Reported as: Unexpected aria-haspopup value

A menu button's aria-haspopup value must name the kind of popup it opens.

When the value is one ARIA allows but doesn't match the popup, such as listbox or dialog on a button that opens a menu, assistive technology tells users to expect a different kind of popup, and they bring the wrong keys and expectations to it.

Set aria-haspopup to menu, or true, which means the same thing, on a button that opens a menu.

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.

Keyboard Navigation Orientation

A menu button's menu moves focus with Up Arrow and Down Arrow, the vertical orientation the menu role implies. When the menu lays its items out in a row instead, aria-orientation="horizontal" declares it, and Left Arrow and Right Arrow move focus.

Declares the orientation it uses

Reported as: Conflicting aria-orientation

The aria-orientation value of a menu button's menu must match the arrow keys that move focus through it.

When the declared orientation and the keys disagree, such as a menu laid out as a row that keeps its implicit vertical orientation while Left Arrow and Right Arrow move focus, screen readers tell users to press keys that don't work.

Set aria-orientation="horizontal" on a menu laid out as a row, and leave it out when the menu is a column.

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

The aria-orientation of a menu button's menu 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 menu is a column.

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 menu button reports whether its menu is open or closed through aria-expanded, and the value changes as the menu is shown and hidden.

aria-expanded reflects displayed state

Reported as: Conflicting aria-expanded value

A menu button's aria-expanded value must reflect whether the menu is displayed: aria-expanded="true" when the menu is open and aria-expanded="false" when it's closed.

When aria-expanded doesn't change as the menu opens and closes, or reports the opposite of what is on screen, screen reader users are told the wrong state and can't rely on the control to know whether the menu is showing.

Keep the attribute in sync with the menu: set it to true when the menu is open and false when it's closed.

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 menu button's aria-expanded value must change when its menu opens or closes.

When the value stays put as the menu appears and disappears, screen reader users are told the menu is closed after they open it, or open after it closes, and can't rely on the button to tell them whether the menu is showing.

Set aria-expanded to true in the code that shows the menu and to false in the code that hides it, however the menu opens or closes.

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 menu button must have an aria-expanded attribute that indicates whether it's expanded or collapsed.

Without an aria-expanded attribute, assistive technologies can't report whether the menu is open or closed, so screen reader users don't know if the menu is available. Add aria-expanded to the button and keep it in sync with the menu's visibility.

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

Like any button, a menu button conveys its disabled state to assistive technologies when it isn't interactive. A disabled menu button doesn't open its menu.

Inside the menu, an item that's unavailable reports that it's disabled with aria-disabled="true" and stays in the menu, where users can still reach it with the arrow keys. Script ignores any attempt to run it.

Avoids conflicting disabled states

Reported as: Conflicting disabled values

A menu button must declare its disabled state one way only: the disabled attribute on a native <button>, or aria-disabled on a custom menu button.

When a native button carries aria-disabled instead of disabled, it stays operable and in the tab order while assistive technology reports it as disabled. When both attributes are set and disagree, assistive technology can report a state the browser doesn't enforce. Either way, screen reader users are told the wrong thing about whether the button opens its menu.

Use disabled alone on a native <button> and aria-disabled alone on a custom menu button, removing it or setting it to false when the button is enabled 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.
Uses aria-disabled rather than disabled

Reported as: Element does not support the disabled attribute

A menu button built from an element that doesn't support the disabled attribute must convey its disabled state with aria-disabled.

When disabled is set on such an element, browsers ignore it, and the button still opens its menu however disabled it looks. Keyboard and screen reader users can then open a menu the design means to be unavailable.

Set aria-disabled="true" instead, and stop the button from opening its menu while it's set, or use a native <button> element.

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 when role allows

Reported as: Component does not support disabled state

In a menu button's menu, only the menu, its groups, and its menu items 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. When none of the menu's commands is available, disable the menu button instead.

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 button 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.
Keeps disabled items findable

Reported as: Disabled menu item not discoverable

A disabled item in a menu button's menu 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, as the example's script does.

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 button's 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 opens from a button and 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.

A button that shows and hides a list of links is a disclosure button, with no aria-haspopup.

Uses links for moving between pages

Reported as: Misused role for site navigation

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

When the menu's 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 the dropdown as a <nav> element containing a list of links, shown and hidden by a button with aria-expanded.

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 menu button must be programmatically associated with the menu it opens so assistive technologies can convey the relationship and users can reach the menu. This association also depends on the button's aria-expanded state tracking the menu's visibility.

Menu button has an associated menu

Reported as: Menu button has no associated menu

A menu button must have an associated menu with role="menu".

When no element with role="menu" is associated with the menu button, screen reader users are told a menu exists but cannot reach it. Give the menu role="menu", place it immediately after the button in the DOM, and set the button's aria-controls to the menu's id.

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 menu button's aria-expanded value must change to true when its menu appears and to false when it disappears.

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

Update aria-expanded in the same code that shows and hides 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.
Has aria-expanded

Reported as: Missing aria-expanded attribute

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

Without it, assistive technology has no state to report, so screen reader users can't tell whether the menu is open or closed.

Set aria-expanded="false" on the button when the page loads, and keep it in step with 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.
Sits beside its launcher

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

A menu button's menu should follow the button immediately in the DOM, with nothing between them.

When the menu is placed elsewhere, often at the end of the page to escape a container that clips it, some assistive technologies lose the association, and users reading the page in order reach the menu's items far from the button that opens them.

Place the menu right after the button, and keep aria-controls on the button pointing to it.

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.

Forbidden Interactive Children

A menu button must not contain other interactive elements. Nested interactive elements create ambiguity about which element will respond to a user's interaction. The menu it opens, placed as a sibling rather than a child, isn't affected by this constraint.

Avoids nested interactives

Reported as: Forbidden interactive children; Nested interactive elements

A menu button must not contain or be nested inside another interactive element, such as a link or another button.

A button has no accessible children. An interactive element nested inside the menu button is presentational, so screen reader users can't perceive or operate it, and a click on it may open the menu instead.

Move the interactive element out of the button, and keep the menu beside the button, not inside it.

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.

Relationships

A menu button and the menu it opens must be programmatically linked so that assistive technologies can convey the relationship and users can reach the menu. Set aria-controls on the button to reference the menu's id, place the menu immediately after the button in the DOM, and give the menu role="menu". For a reliable, two-way association, also set aria-labelledby on the menu to reference the button.

The menu is a sibling of the button, not a child, so use aria-controls for this relationship rather than aria-owns.

aria-owns

A menu button is a single control that opens a menu outside itself, not a container that holds the menu's items. Its aria-controls already states that relationship, and owning the menu with aria-owns would make it one of the button's presentational children. The menu, in turn, holds its items in the DOM, in the order the arrow keys move through them.

Avoids aria-owns

Reported as: Avoid aria-owns

General check. Evinced checks that the menu button doesn't use aria-owns to claim its menu or other elements as its children. This check runs on every UI pattern, not only on menu buttons.

A menu button should not use aria-owns.

When a menu button owns its menu, the menu becomes one of the button's children, and a button's children are presentational. Screen reader users then perceive the menu items only as part of the button's name and can't operate them.

Remove aria-owns from the button, and reference the menu with aria-controls instead.

Owns only conforming roles

Reported as: Invalid aria-owns values

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

When a menu button's 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.

Reference only elements with those roles, and own each element from one container. Better still, render the items inside the menu and remove aria-owns.

Operation

Like any button, a menu button is operable with both a pointer and a keyboard. Clicking or tapping the button activates it. With a keyboard, the Tab key moves focus to and away from a button, and pressing Enter or Space activates it.

Semantic HTML buttons provide this keyboard behavior automatically. A custom button built with role="button" must reproduce it: add tabindex="0" so the element joins the tab order, and add event listeners to enable activation with the Enter or Space key. By convention, a button is activated on an Enter keydown event and a Space keyup event.

A menu button adds operational expectations and accessibility requirements.

With a pointer, clicking or tapping the button opens the menu and moves focus to the first available menu item. Clicking or tapping a menu item runs its command and, in most cases, closes the menu and returns focus to the button. Clicking outside the button and its menu closes the menu without running a command.

With keyboard focus on a menu button, either the Enter or Space key opens its menu and places effective focus on the first menu item. Optionally, the Down Arrow key does the same, and the Up Arrow key opens the menu with effective focus on the last item.

A menu item has effective focus when it has actual keyboard focus, or when keyboard focus is on the menu itself and aria-activedescendant identifies the item.

The following table shows expected keyboard behavior when focus is on the menu or a menu item.

KeyFunction
Down ArrowMoves effective focus to the next or, if on the last, the first menu item
Up ArrowMoves effective focus to the previous or, if on the first, the last menu item
Home (optional)Moves effective focus to the first menu item
End (optional)Moves effective focus to the last menu item
EnterActivates the focused menu item, closes the menu, and sets focus on the menu button
SpaceActivates the focused menu item, closes the menu, and sets focus on the menu button. On a menuitemcheckbox or menuitemradio, changes its state and can keep the menu open
EscapeCloses the menu and sets focus on the menu button
TabCloses the menu and moves focus to the next element in the tab order

Focus Sequence

A menu button is reachable in the standard tab order so keyboard users can focus it. When the menu opens, focus moves into it. When it closes, focus returns to the button. Neither the menu nor its items are tab stops of their own.

Reachable by keyboard

Reported as: Keyboard accessible

A menu button must be reachable with the Tab key.

When the button is built from markup that isn't focusable, such as a <div> or <span>, keyboard users can't reach it, so they can't open its menu or use any of its commands.

Use a <button> element, which is focusable by default, or add tabindex="0" to a custom button.

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.
Takes focus when it opens

Reported as: Composite not in focus sequence

A menu button's menu must be able to take keyboard focus once it opens, on the menu itself or on one of its items.

When neither the menu nor its items can take focus, such as a <div> with role="menu" and no tabindex holding <div> items, focus can't move into the open menu. Keyboard users can open it but can't reach any of its commands.

Give the menu tabindex="-1" and identify the focused item with aria-activedescendant, as the example does, or give each item tabindex="-1" and move focus to the item itself.

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 a menu item

Reported as: Composite unpredictable focus

When focus moves into a menu button's menu, it must land on a menu item.

When focus reaches the menu container and no item has effective focus, because aria-activedescendant is missing or names an id that doesn't exist, screen reader users hear the menu's name and no item. Keyboard users can't tell where the next arrow key press will take them.

Set aria-activedescendant to the item that should have focus in the same step that focuses the menu, or focus the item itself.

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.
Keeps its items out of the tab order

Reported as: Redundant focusable children

The items of a menu button's menu must not be stops in the tab order.

When the items are <button> elements, as in the example's markup, they're tab stops by default. Tab then moves from item to item instead of leaving the menu, and nothing tells keyboard users to use the arrow keys.

Set tabindex="-1" on every item, as the example's script does, and move focus between them with the arrow keys.

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.
Skips tab order when disabled

Reported as: Disabled element focusable

A menu button that presents as disabled should not be in the tab order.

When a disabled menu button keeps its tab stop, keyboard users land on a control that won't open its menu.

Use the disabled attribute on a native <button>, which removes it from the tab order. On a custom button, set tabindex="-1" while aria-disabled="true" is set, and restore tabindex="0" when it's enabled.

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.
Puts focus on element with button role

Reported as: Focusable offset

The element that carries a menu button's button role must be the element that receives focus, not one of its descendants.

When a descendant takes focus instead, keyboard users reach the control but may not be able to open the menu with Enter or Space, and screen reader users aren't told its role or whether its menu is open.

Use a <button> element, or set tabindex="0" on the element that carries the role, aria-haspopup, and aria-expanded, and remove focusability from the descendant.

Severity: Minor

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.

Focus Management

When the menu opens, effective focus should move into the menu and, in most cases, return to the menu button when the menu closes.

A menu button together with its menu forms a composite widget. Manage focus so that the composite is a single tab stop in the page tab order and users can change the effective focus within it using arrow keys or a pointer device (mouse). You can manage focus programmatically either by using an aria-activedescendant technique or by setting element focus with JavaScript.

Refer to Keyboard Navigation Inside Components for more information.

Moves focus on open

Reported as: Focus on menu open

A menu button must move focus into the menu or submenu when it's opened with the keyboard.

If focus doesn't move into the menu when it opens, keyboard users have to search for the newly revealed options. Move focus to the first actionable menu item, or to the menu container, as the menu opens.

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

When the Escape key is pressed, focus must return to the menu button or submenu parent.

If focus isn't returned to the menu button when the Escape key closes the menu, keyboard and screen reader users are left without a clear focus point and can be dropped at the top of the page. Move focus back to the button whenever the menu closes without another explicit destination.

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

A menu button must set effective focus to the first menu item when a menu or submenu is opened with the keyboard, or to the last menu item when the Up Arrow key opens it.

If focus lands anywhere else when the menu opens, it breaks the expected reading and navigation order. Place initial focus on the first actionable item, or on the last when the Up Arrow key opens the menu, so keyboard users start where they expect.

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 effective focus from item to item in a menu button's menu, in the direction the items are laid out, wrapping at the ends, and disabled items stay in the sequence. For a script that handles Down Arrow, Up Arrow, Home, and End on keydown on the menu, see Examples.

Moves focus to the expected item

Reported as: Menu unexpected focus shift

Each arrow key press in a menu button's 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 item in a menu button's menu must stay reachable with the arrow keys that move through the 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 the orientation of a menu button's menu move focus from item to item. This check runs on several UI patterns.

A menu button's 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, or Left Arrow and Right Arrow in a menu laid out as a row, on keydown on the menu.

Keyboard Activation

A menu button meets every keyboard-activation requirement of an ordinary button. Unless it's disabled, it opens and closes its menu with either the Enter or Space key, and the Down Arrow or Up Arrow key may also open the menu. Activating it updates the button's aria-expanded state.

Operable by keyboard

Reported as: Button not activated by keyboard

A menu button must open its menu from the keyboard.

When a custom menu button responds only to a click, keyboard users can reach it but can't open its menu, so its commands are out of their reach.

Use a <button> element, which responds to Enter and Space on its own, or add keyboard event listeners to a custom button that open the menu as a click does.

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.
Activation updates aria-expanded

Reported as: Aria-expanded value did not change

A menu button must update the aria-expanded attribute to reflect its current expanded or collapsed state.

If the aria-expanded value doesn't change when the button is activated from the keyboard, screen reader users get no confirmation that their key press toggled the menu. Update aria-expanded to true when activation opens the menu and false when it closes.

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 menu button must carry an aria-expanded attribute, so activating it from the keyboard has a state to update.

Without it, screen reader users who press Enter or Space get no confirmation that the menu opened, or that it closed when they press the key again.

Add aria-expanded="false" to the button, and set it to true when the keyboard opens 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.
Ignores keyboard when disabled

Reported as: Disabled button keyboard activation

A menu button that reports itself as disabled should not open its menu from the keyboard.

When a custom menu button carries aria-disabled="true" but Enter or Space still opens the menu, screen reader users are told one thing and get another, and may lose trust in the interface.

Use a native <button> with the disabled attribute, which blocks activation on its own. On a custom button, have the keyboard handlers check aria-disabled and return before opening the menu.

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.
Activates with Enter and Space

Reported as: Button requires space key activation

A custom menu button must open its menu with the Space key, as a <button> element does, not only with Enter.

Users who press Space, as they would on any other button, get no menu and may conclude the control is broken.

Use a native <button> element, or add a Space keyup handler that opens the menu.

Severity: Minor

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.

Checked Menu Items

A menu button's menu can hold options as well as commands: a menuitemcheckbox turns a setting on or off, and a menuitemradio picks one setting from a group. Each 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.

Toggles a checkable menu item

Reported as: Menuitemcheckbox Not Toggled

A checkable item in a menu button's menu must change its aria-checked value when it's operated, and Space should 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 in a menu button's menu 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 button 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 button'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 button 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 button issues relate to?

Under 4.1.2 Name, Role, Value, a menu button carries the button role and an accessible name, conveys its disabled state correctly, and contains no interactive elements. Its menu's items each have a name, declare a disabled state only where their role allows it, report a checkable item's state with aria-checked, and are never links to other pages dressed as menu items.

Under 1.3.1 Info and Relationships, it has an aria-expanded value that matches its menu and changes when the menu opens or closes, it's associated with a menu that has the menu role, its aria-haspopup value names the kind of popup it opens, and opening the menu puts effective focus on the right item. Its menu contains items with a menu item role, has a name, keeps disabled items reachable with the arrow keys, and keeps its items out of the tab order.

Under 2.1.1 Keyboard, a menu button can be reached with the Tab key, takes focus itself, opens its menu with Enter and Space, moves focus into the menu when it opens, and gets focus back when Escape closes it. Its menu takes focus when it opens and lands on an item, the arrow keys move between items in the direction the menu declares, and Space toggles a checkable item.

The rest are best practices that map to no success criterion: declaring the popup with a valid aria-haspopup value, placing the menu right after the button, keeping a disabled menu button out of the tab order and away from keyboard activation, giving the menu's items distinct names, and using a valid aria-orientation value.

Why are some menu button 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 button with no role or name, an aria-expanded value that contradicts the screen, no associated menu, a button that keyboard users can't reach or activate, a menu that can't take focus, menu items with no name, arrow keys that send focus somewhere unexpected, or a checkable item that doesn't toggle or report its state.

Serious issues mislead or strand users, such as a missing or unchanging aria-expanded value, a wrong disabled state, nested interactive elements, focus that doesn't move into the menu when it opens, a disabled menu button that still opens from the keyboard, a menu with no name or no menu items, two items with the same name, focus that lands on no item, an aria-orientation value that contradicts the arrow keys, or menu roles used for site navigation.

Moderate issues weaken orientation, such as a missing aria-haspopup, focus that lands on the wrong item or isn't restored after Escape, or menu items left in the tab order.

Minor issues break a convention without blocking the task, such as an aria-haspopup value that doesn't fit, a menu placed away from its button, a disabled button left in the tab order, focus that lands inside the button, a button that ignores the Space key, an invalid aria-orientation value, or disabled items the arrow keys skip.

Four checks carry no severity: the two general checks for aria-owns, and the sanity checks on where the button role sits and on the arrow keys moving focus in the menu.

  • Button: the base pattern a menu button builds on, including its role, name, disabled state, and keyboard activation
  • Menu: the popup a menu button opens, and how its items work
  • Site Navigation: how to build navigation that opens in a popup without menu roles
  • Disclosure: a button that shows and hides content rather than opening a menu
  • Combobox: a control that opens a list of values to select
  • Listbox: the list of values a combobox often opens