Pattern: Tab Navigation
Tab navigation interfaces are widgets that enable authors to display multiple logically similar panels within a single window, whereby only a single panel is displayed at any one time. Tabbed interfaces draw on the metaphor of card indexes, in which each individual tab’s title is commonly displayed horizontally across the top of the widget (although occasionally vertically down the left-hand side). The user navigates through this list, and makes the related content visible by selecting the relevant title.
How it looks
<ul class="tabs" role="tablist">
<li role="presentation" class="active"><a href="#" onclick="displayPanel(1);" role="tab" id="tab1" tabindex="0" aria-controls="panel1" aria-selected="true">Flags</a></li>
<li role="presentation"><a href="#" onclick="displayPanel(2);" role="tab" id="tab2" tabindex="-1" aria-controls="panel2" aria-selected="false">Props</a></li>
<li role="presentation"><a href="#" onclick="displayPanel(3);" role="tab" id="tab3" tabindex="-1" aria-controls="panel3" aria-selected="false">Banners</a></li>
<div role="tabpanel" id="panel1" aria-labelledby="tab1" aria-hidden="false" aria-expanded="true">
<div role="tabpanel" id="panel2" aria-labelledby="tab2" aria-hidden="true" aria-expanded="false">
<div role="tabpanel" id="panel3" aria-labelledby="tab3" aria-hidden="true" aria-expanded="false">
As tabs are a collection of links, mark them up as an unordered list and provide this list with the container role of tablist. This indicates to screen reader software that each of the items in the list is a selectable tab.
To ensure the tabs are keyboard accessible, either add extra scripting to the <li> so that it is placed in the keyboard tab order, or use regular anchor elements within each list item. Given that, by default, anchor elements are keyboard accessible (and therefore do not require extra scripting to make them so), we strongly recommend the latter approach. The rest of the advice in this technique therefore assumes an anchor element will be used within a list item.
Provide each <li> element in the tablist with a role of presentation so that the list semantics are suppressed and no longer conveyed to assistive technologies, and are therefore ignored.
To ensure that assistive technologies convey link anchors as tabs rather than links, add the role of tab to each link in the list. Further attributes are also required to provide additional necessary semantic information. These attributes are as follows:
- Provide each tab with a unique identifier (id).
- aria-selected indicates whether or not the related tab is currently selected (and the related tab panel is displayed on the page). Set this attribute to true when the tab is selected, otherwise set it to false. Dynamically update this value via scripting based on user navigation. Only one tab at a time can be selected, hence only one of the items in the list can have aria-selected set to true at any one time.
- aria-controls indicates which of the panels is displayed when this tab is selected. This attribute is set to the id value of the relevant panel.
- tabindex indicates whether or not the tab is included in the tab order. This is set to a value of 0 for the currently selected tab, and -1 for the remaining tabs. As a result, the remaining tabs are not included in the keyboard tab order, but can receive programmatic focus through scripting (objTab.focus();`). Keyboard interaction is discussed in more detail shortly.
The panels that are controlled by the tabs in the tab list should be contained within a <div> element provided with a role of tabpanel. Set the following attributes on each panel:
- Provide each panel with a unique identifier (id).
- aria-labelledby indicates the tab to which this panel relates. This is set to a value that matches the id value of the related tab.
- aria-hidden indicates whether the panel is visible (i.e., the tab is selected), in which case the value is set to true, or not (i.e., it is not selected), in which case the value is set to false. Use display: none; in CSS to achieve the same effect visually; do not hide the content offscreen, as the content will still be available to screen readers in the event the aria-hidden attribute is ignored.
- aria-expanded, while not absolutely necessary, provides extra semantic information by indicating whether the element is currently expanded (in which case the value is set to true) or collapsed (in which case the value is set to false).
Make sure the interface uses the following keystrokes:
- Tab key: Pressing the Tab key moves focus to the active tab in the tab list. Pressing the Tab key again moves focus to the first focusable element in the associated tab panel, not to the next tab in the list. If there are no focusable items in the associated tab panel, pressing tab moves to the next focusable item after the tabbed interface widget on the page.
- Left arrow key: When focus is on a tab in the tab list, focus should move to the previous tab in the list. When the first tab in the list has focus and the left arrow key is pressed, the last tab in the tab list should receive focus.
- Right arrow key: When focus is on a tab in the tab list, focus should move to the next tab in the list. When the last tab in the list has focus and the right arrow key is pressed, the first tab in the tab list should receive focus.
- Up arrow key: The same behavior as pressing the left arrow key.
- Down arrow key: The same behavior as pressing the right arrow key.