You are here

Menu bar, Tree menu and Sortable list

Menu Bars

Menu bars are typically presented horizontally across the top of a website or web application, containing links to key areas of the website or application, or function as toggles that open submenus, or both links and toggle, and remain in view across the entire website or application. 

Roles, states, and properties used in a menu bar

  • aria-hidden = [true | false]
  • role = "menubar"
  • role = "menu"
  • role= = "menuitem"
  • aria-labelledby = "[instruction div id]"
  • aria-label = [link text]
  • tabindex = [0 | -1]
  • aria-haspopup = "true"
  • aria-expanded = "[true | false]"
  • aria-selected = "[true | false]"

The following JSFiddle presents a typical menu bar widget with a variety of sub menus. Review the JavaScript and HTML markup, and test the menu bar presented under the Result tab with ChromeVox to understand how it functions without any accessibility features added. You can work in JSFiddle itself by clicking the “Edit in JSFiddle” at the top, right-hand side, copying the accessibility/WAI-ARIA code described below to fix the accessibility of the menu bar before completing Activity 12 on the page that follows.Skip JSFiddle

First provide some instructions on how to use the menu with a keyboard and add them to the default options.

Hide the instructions from screen readers until needed, adding aria-hidden="true" to the instructions <div> defined when the menu is initialized.

Add the role="menubar" to the top level <UL> in the menu, and make that UL keyboard focusable with tabindex="0" so it reads the instructions while in focus being referenced with aria-labelledby.

For all the menu items in the menu bar that have submenus, add role="menu" to their <UL> and hide them by default using aria-hidden="true". This can be located after the $elem.find('ul:eq(0)') block presented immediately above.

Hide the links in the menu items from screen readers by default using tabindex="-1" and setting aria-hidden="true".

Set up the menu items throughout the menu using role="menuitem". Also remove keyboard access by default with tabindex="-1" and label each menu item with the text of the associated link using aria-label="[$link.text]".

For each of the menu items that has a submenu, add aria-haspopup="true" to announce the presence of the submenu, and set its default state to “collapsed” by adding aria-expanded="false".

When a menu item is marked selected, also add aria-selected="true" and add keyboard access back to the menu item with tabindex="0".

Add keyboard access back to menu items using tabindex="0".

Reference the keyboard access class, where mouse events are defined in the onKeyDown function, described below.

In the showSubMenu function, add aria-expanded="true" submenus when they are expanded, remove keyboard access from the submenu container with tabindex="-1". And make the submenu visible with aria-hidden="false".

In the hideSubMenu function, set aria-expanded="false", hide submenus with aria-hidden="true", and remove keyboard access with tabindex="-1" when a submenu is closed.

When the collapseAll function is called, to collapse any open menus, reverse all attributes defining the element as open, reverting to aria-hidden="true", aria-expanded="false" and re-adding keyboard access with tabindex="0" so it can be opened again.

Adding Keyboard Operability

Menu bar keyboard functionality can be complex, particularly with large menus with multiple levels of submenus, and they can include redundant keys that perform the same function. The W3C defines suggested keyboard interaction for a menu bar as follows:

Menu Bar Keyboard Interaction

The following description of keyboard behaviours assumes:

  1. A horizontal menubar containing several menuitem elements.
  2. All items in the menubar have child submenus that contain multiple vertically arranged items.
  3. Some of the menuitem elements in the submenus have child submenus with items that are also vertically arranged.

When reading the following descriptions, also keep in mind that:

  1. Focusable elements, which may have role menuitem, menuitemradio, or menuitemcheckbox, are referred to as items.
  2. If a behaviour applies to only certain types of items, e.g., menuitem elements, the specific role name is used.
  3. Submenus, also known as pop-up menus, are elements with role menu.
  4. Except where noted, menus opened from a menu button behave the same as menus opened from a menu bar.
  • When a menu opens, or when a menubar receives focus, keyboard focus is placed on the first item. All items are focusable as described in 5.6Keyboard Navigation Inside Components (Links to an external site.)Links to an external site..
  • Enter:
    • When focus is on a menuitem that has a submenu, opens the submenu and places focus on its first item.
    • Otherwise, activates the item and closes the menu.
  • Space:
    • (Optional): When focus is on a menuitemcheckbox, changes the state without closing the menu.
    • (Optional): When focus is on a menuitemradio that is not checked, without closing the menu, checks the focused menuitemradio and unchecks any other checked menuitemradio element in the same group.
    • (Optional): When focus is on a menuitem that has a submenu, opens the submenu and places focus on its first item.
    • (Optional): When focus is on a menuitem that does not have a submenu, activates the menuitem and closes the menu.
  • Down Arrow:
    • When focus is on a menuitem in a menubar, opens its submenu and places focus on the first item in the submenu.
    • When focus is in a menu, moves focus to the next item, optionally wrapping from the last to the first.
  • Up Arrow:
    • When focus is in a menu, moves focus to the previous item, optionally wrapping from the first to the last.
    • (Optional): When focus is on a menuitem in a menubar, opens its submenu and places focus on the last item in the submenu.
  • Right Arrow:
    • When focus is in a menubar, moves focus to the next item, optionally wrapping from the last to the first.
    • When focus is in a menu and on a menuitem that has a submenu, opens the submenu and places focus on its first item.
    • When focus is in a menu and on an item that does not have a submenu, performs the following 3 actions:
      1. Closes the submenu and any parent menus.
      2. Moves focus to the next menuitem in the menubar.
      3. Either: (Recommended) opens the submenu of that menuitem without moving focus into the submenu, or opens the submenu of that menuitem and places focus on the first item in the submenu.

      Note that if the menubar were not present, e.g., the menus were opened from a menubutton, Right Arrow would not do anything when focus is on an item that does not have a submenu.

  • Left Arrow:
    • When focus is in a menubar, moves focus to the previous item, optionally wrapping from the last to the first.
    • When focus is in a submenu of an item in a menu, closes the submenu and returns focus to the parent menuitem.
    • When focus is in a submenu of an item in a menubar, performs the following 3 actions:
      1. Closes the submenu.
      2. Moves focus to the previous menuitem in the menubar.
      3. Either: (Recommended) opens the submenu of that menuitem without moving focus into the submenu, or opens the submenu of that menuitem and places focus on the first item in the submenu.
  • Home: If arrow key wrapping is not supported, moves focus to the first item in the current menu or menubar.
  • End: If arrow key wrapping is not supported, moves focus to the last item in the current menu or menubar.
  • Any key that corresponds to a printable character (Optional): Move focus to the next menu item in the current menu whose label begins with that printable character.
  • Escape: Close the menu that contains focus and return focus to the element or context, e.g., menu button or parent menuitem, from which the menu was opened.
  • Tab: Moves focus to the next element in the tab sequence, and if the item that had focus is not in a menubar, closes its menu and all open parent menu containers.
  • Shift + Tab: Moves focus to the previous element in the tab sequence, and if the item that had focus is not in a menubar, closes its menu and all open parent menu containers.
Note
  1. Disabled menu items are focusable but cannot be activated.
  2. A separator (Links to an external site.)Links to an external site. in a menu is not focusable or interactive.
  3. If a menu is opened or a menu bar receives focus as a result of a context action, Esc or Enter may return focus to the invoking context. For example, a rich text editor may have a menu bar that receives focus when a shortcut key, e.g., Alt+F10, is pressed while editing. In this case, pressing Esc or activating a command from the menu may return focus to the editor.
  4. Although it is recommended that authors avoid doing so, some implementations of navigation menu bars may have menuitem elements that both perform a function and open a submenu. In such implementations, Enter and space bar perform a navigation function, e.g., load new content, while Down Arrow, in a horizontal menu bar, opens the submenu associated with that same menuitem.
  5. When items in a menubar are arranged vertically and items in menu containers are arranged horizontally:
    1. Down Arrow performs as Right Arrow is described above, and vice versa.
    2. Up Arrow performs as Left Arrow is described above, and vice versa.

Source: W3C WAI-ARIA 1.1 Authoring Practices (Links to an external site.)Links to an external site.

Here we have implemented a subset of the keyboard interaction W3C recommends in an onKeyDown() function that is called when event handlers are set up for menu items. These keys include Left and Right Arrows, Up and Down Arrows, the space bar and Enter keys, and Tab and Esc keys. Copy the following function into the ik_menu.js file, near the end, to add keyboard operability to the menu.

Accessible Menu Bar in Action

Watch the following video showing ChromeVox interacting with a menu bar. The Tab key is used to navigate into the menu bar, to the first menu item, and to exit the menu bar. The Left and Right Arrow keys are used to move across the top level menu items, and Up and Down arrows are used to move into and out of a submenu, and to move between menu items in a submenu. The space bar or Enter key are used to activate a menu item. The Esc key closes the current submenu. Aim to have the menu bar you update in the activity coming up on the next page operate and announce itself like the one in the video.

 

 

Tree Menus

Tree menus often have the same underlying HTML structure as a menu bar, but rather than being arranged in a horizontal layout, they tend to be arranged vertically.

WAI-ARIA roles, states, and properties used in a tree menu

  • tabindex = [0 | -1]
  • aria-labelledby = [instruction div id | title div id]
  • aria-hidden = [true | false]
  • role = "tree"
  • role = "treeitem"
  • role = "presentation"
  • aria-level = [number of parent ULs]
  • aria-setsize = [number of LIs in a level]
  • aria-posinset = [position of each LI in a set]
  • aria-expanded = [true | false]
  • aria-selected = [true | false]

The following JSFiddle presents a typical tree menu widget with a few submenus. Review the JavaScript and HTML markup, and test the tree menu presented under the Result tab with ChromeVox to understand how it functions without any accessibility features added. You can work in JSFiddle itself by clicking the “Edit in JSFiddle” at the top, right-hand side, copying the accessibility/WAI-ARIA code described below to fix the accessibility of the tree menu before completing Activity 13 on the page that follows.Skip JSFiddle

First define instructions on using the tree menu with a keyboard.

Within the init() function add keyboard focus to the tree container by applying tabindex="0" to it and label the container with the instructions created above, which gets read by screen readers when the menu initially receives focus.

Within the init() function, hide the instructions <div> from screen readers by default by setting aria-hidden="true" when the tree menu is initialized.

Within the init() function replace the unordered list semantics with tree menu semantics using role="tree", and give it a title using aria-labelledby to reference the title defined in the default options.

Within the init() function, define menu items with role="treeitem", remove all keyboard access by default with tabindex="-1", set the number of levels in the tree based on the number of parent ULs with aria-level=[number of ULs], set the number of tree items on a given level with aria-setsize="[number of LIs in a UL]", and finally define the position of each tree item within a level using aria-posinset="[child LI index]".

Within the init() function, if a tree item has a submenu UL that has been opened, set aria-expanded="true", otherwise set aria-expanded="false".

Within the init() function, for each tree item use the text of the associated <span> element as its label. To ensure both the label and the contents of the <span> element are not both read, assign role="presentation" to the <span>.

Within the init() function, where mouse onclick functionality is used, provide equivalent keydown functionality, here referencing the onKeyDownfunction, shown below, that defines the keys to operate the menu.

Within the init() function, right after adding keydown operability, make the first item in the tree menu focusable by adding tabindex="0" to the first <li>.

Within the selectItem() function, set up a roving tabindex, while at the same time applying aria-selected=[true | false] when tree items receive or lose focus.

In the toggleSubmenu() function announce the state of submenus to the screen reader by toggling the aria-expanded=[true | false] attribute when a menu is opened or closed.

Adding Keyboard Operability

Much like the menu bar described in the previous activity, keyboard operability for a tree menu can be complex, with various operations using multiple key strokes to perform the same function. W3C describe potential keyboard operation in the WAI-ARIA Authoring Practices 1.1 (Links to an external site.)Links to an external site., reproduced below.

Tree Menu Keyboard Interaction

For a vertically oriented tree:

  • When a single-select tree receives focus:
    • If none of the nodes are selected before the tree receives focus, focus is set on the first node.
    • If a node is selected before the tree receives focus, focus is set on the selected node.
  • When a multi-select tree receives focus:
    • If none of the nodes are selected before the tree receives focus, focus is set on the first node.
    • If one or more nodes are selected before the tree receives focus, focus is set on the first selected node.
  • Right Arrow:
    • When focus is on a closed node, opens the node; focus does not move.
    • When focus is on a open node, moves focus to the first child node.
    • When focus is on an end node, does nothing.
  • Left Arrow:
    • When focus is on an open node, closes the node.
    • When focus is on a child node that is also either an end node or a closed node, moves focus to its parent node.
    • When focus is on a root node that is also either an end node or a closed node, does nothing.
  • Down Arrow: Moves focus to the next node that is focusable without opening or closing a node.
  • Up Arrow: Moves focus to the previous node that is focusable without opening or closing a node.
  • Home: Moves focus to the first node in the tree without opening or closing a node.
  • End: Moves focus to the last node in the tree that is focusable without opening a node.
  • Enter: Activates a node, i.e., performs its default action. For parent nodes, one possible default action is to open or close the node. In single-select trees where selection does not follow focus (see note below), the default action is typically to select the focused node.
  • Type-ahead is recommended for all trees, especially for trees with more than 7 root nodes:
    • Type a character: focus moves to the next node with a name that starts with the typed character.
    • Type multiple characters in rapid succession: focus moves to the next node with a name that starts with the string of characters typed.
  • * (Optional): Expands all siblings that are at the same level as the current node.
  • Selection in multi-select trees: Authors may implement either of two interaction models to support multiple selection: a recommended model that does not require the user to hold a modifier key, such as Shift or Ctrl, while navigating the list or an alternative model that does require modifier keys to be held while navigating in order to avoid losing selection states.
    • Recommended selection model – holding a modifier key while moving focus is not necessary:
      • Space: Toggles the selection state of the focused node.
      • Shift+Down Arrow (Optional): Moves focus to and toggles the selection state of the next node.
      • Shift+Up Arrow (Optional): Moves focus to and toggles the selection state of the previous node.
      • Shift+Space (Optional): Selects contiguous nodes from the last selected node to the current node.
      • Ctrl+Shift+Home (Optional): Selects the node with focus and all nodes up to the first node.
      • Ctrl+Shift+End (Optional): Selects the node with focus and all nodes down to the last node.
      • Ctrl+A (Optional): Selects all nodes in the tree. Optionally, if all nodes are selected, it can also unselect all nodes.
    • Alternative selection model – moving focus without holding the Shift or Ctrl modifier unselects all selected nodes except for the focused node:
      • Shift+Down Arrow: Moves focus to and toggles the selection state of the next node.
      • Shift+Up Arrow: Moves focus to and toggles the selection state of the previous node.
      • Ctrl+Down Arrow: Without changing the selection state, moves focus to the next node.
      • Ctrl+Up Arrow: Without changing the selection state, moves focus to the previous node.
      • Ctrl+Space: Toggles the selection state of the focused node.
      • Shift+Space (Optional): Selects contiguous nodes from the most recently selected node to the current node.
      • Ctrl+Shift+Home (Optional): Selects the node with focus and all nodes up to the first node.
      • Ctrl+Shift+End (Optional): Selects the node with focus and all nodes down to the last node.
      • Ctrl+A (Optional): Selects all nodes in the tree. Optionally, if all nodes are selected, it can also unselect all nodes.
Note
  1. DOM focus (the active element) is functionally distinct from the selected state. For more details, see this description of differences between focus and selection. (Links to an external site.)Links to an external site.
  2. The tree role supports the aria-activedescendant (Links to an external site.)Links to an external site. property, which provides an alternative to moving DOM focus among treeitemelements when implementing keyboard navigation. For details, see Managing Focus in Composites Using aria-activedescendant (Links to an external site.)Links to an external site..
  3. In a single-select tree, moving focus may optionally unselect the previously selected node and select the newly focused node. This model of selection is known as "selection follows focus". Having selection follow focus can be very helpful in some circumstances and can severely degrade accessibility in others. For additional guidance, see Deciding When to Make Selection Automatically Follow Focus (Links to an external site.)Links to an external site..
  4. If selecting or unselecting all nodes is an important function, implementing separate controls for these actions, such as buttons for "Select All" and "Unselect All", significantly improves accessibility.
  5. If the nodes in a tree are arranged horizontally:
    1. Down Arrow performs as Right Arrow is described above, and vice versa.
    2. Up Arrow performs as Left Arrow is described above, and vice versa.

Source: WAI-ARIA Authoring Practices 1.1 (Links to an external site.)Links to an external site.

For the tree menu created here, we’ve added in basic keyboard operability. Keyboard operation includes:  Up and Down, and Left and Right Arrows for navigating within the tree, and the Enter or space bar keys to toggle submenus open or closed. The Tab key by default enters and exits the tree menu and does not need to be defined as part of the keyboard operability of the tree menu.

Accessible Tree Menu in Action

Watch the following video showing ChromeVox interacting with a tree menu. The Tab key is used to navigate into the tree menu, to the first tree item, and to exit the tree menu. The Up and Down Arrows are used to move between tree items. The space bar or Enter key are used to expand and collapse a tree item with a submenu. When a submenu is opened, focus moves to the first tree item in the menu. Aim to have the tree menu you update in the activity coming up on the next page operate and announce itself like the one in the video.

 

 

Sortable Lists

One of the more common types of widgets that present barriers for screen reader users are drag and drop features. These can be set up in a grid, where draggable items can be rearranged horizontally or vertically by clicking on an item and moving it to a new position in the grid. A drag and drop may also be a sortable list, where items in a list can be dragged vertically to perhaps position the more important list items near the top of the list. For drag and drop elements you may come across on the Web today, the vast majority only function with a mouse, making them inaccessible to many people who rely on a keyboard to navigate. Here we will look at a sortable list, and the WAI-ARIA and associated keyboard operability required to make that list sortable while using only a screen reader and a keyboard.

Role, states, and properties used in a sortable list

  • role = "list"
  • role = "listitem"
  • tabindex = "[0 | -1]"
  • aria-labelledby = "[instruction div id]"
  • aria-hidden = "[true | false]"

The following JSFiddle presents a typical sortable list widget. Review the JavaScript and HTML markup, and test the list presented under the Result tab with ChromeVox to understand how it functions without any accessibility features added. You can work in JSFiddle itself by clicking the “Edit in JSFiddle” at the top, right-hand side, copying the accessibility/WAI-ARIA code described below to fix the accessibility of the menu bar before completing Activity 14 on the page that follows.Skip JSFiddle

As usual, create instructions on using the sortable list with a keyboard. In this case we also want to determine which modifier key to include in the instructions. For Mac it will be the Command key, otherwise it will be the Ctrl key. Here the standard accesskey key commands will also work as the modifier and can potentially be described as well (e.g. Ctrl+Alt on Mac, or Ctrl on Windows).

Assign a redundant role="list" to the opening UL, make the UL keyboard focusable, and attach the instruction with aria-labelledby="[instruction div id]" so keyboard navigation details are announced when the list initially receives focus while using a screen reader.

Within the init() function, generate the <div> that will contain the instructions, and add aria-hidden="true" to hide it from screen readers by default.

In the items section of the init() function, where draggable is defined for each item in the list, add a redundant role="listitem", and generate a label for each item that describes the list item’s current position and that that list item is “movable.” Finally set tabindex="0" on the first list item, and tabindex="-1"on the other list items, to ensure a list item is focusable by default.

Where the draggable attributes are defined near the end of the init() function, attach a keydown reference to the onKeyDown() function to make the list draggable with a keyboard.

In the resetNumbering() function, update the label for moved items to reflect their new position in the list using aria-label = "[new position]".

Adding Keyboard Operability

Keyboard operation for a drag and drop sortable list is relatively simple, compared to the menu bar and tree menu. Essentially only the Up and Down Arrow keys are needed. The standard operating system modifier keys, typically used with tabindex (e.g. Crtl+Alt, or Alt, or Ctrl), function as the modifier keys when using them in addition to the Up and Down Arrows to grab, drag, and drop a list item.

The onKeyDown() function for the sortable list presented below, defines just up and down arrow key operability, along with a roving tabindex. W3C has not yet created a best practice for authoring keyboard interaction for drag and drop elements.

Sortable List in Action

Watch the following video showing ChromeVox interacting with a sortable list. The Tab key is used to navigate into the list, and to exit the list. The Up and Down Arrows are used to move between list items. On a Mac, the Command key plus Up or Down Arrow, selects a list item and moves it to a new location. On windows the Ctrl key is used instead of Command, along with the Up or Down Arrow keys to move list items. Aim to have the sortable list you update in the activity coming up on the next page operate and announce itself like the one in the video.