ARIA: tab role - Accessibility 编辑
The ARIA tab
role indicates an interactive element inside a tablist that, when activated, displays its associated tabpanel.
<button role="tab" aria-selected="true" aria-controls="tabpanel-id" id="tab-id">Tab label</button>
Description
An element with the tab
role controls the visibility of an associated element with the tabpanel
role. The common user experience pattern is a group of visual tabs above, or to the side of, a content area, and selecting a different tab changes the content and makes the selected tab more prominent than the other tabs.
Elements with the role tab
must either be a child of an element with the tablist
role, or have their id
part of the aria-owns
property of a tablist
. This combination identifies to assistive technology that the element is part of a group of related elements. Some assistive technology will provide a count of the number of tab
role elements inside a tablist
, and inform users of which tab
they currently have targeted. They should contain the aria-controls
property identifying an element with the tabpanel
role. When an element with the tabpanel
role has focus, or a child of it has focus, that indicates that the connected element with the tab
role is the active tab in a tablist
.
When working with elements with the tab
role, when they are selected or active, they should have their aria-selected
attribute set to true
, otherwise it should be set to false
. When a tab
is selected or active, its controlled tabpanel
should have its aria-expanded
attribute set to true and its hidden
attribute set to false
, otherwise the reverse.
Associated Roles and Attributes
- aria-selected
- boolean
- aria-controls
id
of element withtabpanel
role- id
- content
Keyboard interaction
Key | Action |
---|---|
Tab | When focus is outside of the tablist moves focus to the active tab. If focus is on the active tab moves focus to the next element in the keyboard focus order, ideally the active tab's associated tabpanel . |
→ | Focuses and optionally activates the next tab in the tab list. If the current tab is the last tab in the tab list it activates the first tab. |
← | Focuses and optionally activates the previous tab in the tab list. If the current tab is the first tab in the tab list it activates the last tab. |
Delete | When allowed removes the currently selected tab from the tab list. |
Required JavaScript features
While there are ways to build tab-like functionality without JavaScript, there are no substitute combination of HTML and CSS only that will provide the same set of functionality that's required above for accessible tabs with content.
Example
This example combines the role tab
with tablist
and elements with tabpanel
to create an interactive group of tabbed content. Here we are enclosing our group of content in a div
, with our tablist
having an aria-label
to label it for assistive technology. Each tab
is a button
with the attributes previously mentioned. The first tab
has tabindex=0
on it, which we will later change to whatever tab has aria-selected=true
. All of the tabpanel
elements have tabindex=0
to make them tabbable, and all but the currently active one have the hidden
attribute, which we will change with JavaScript. There is some basic styling applied that restyles the buttons and changes the z-index
to of tab
elements to give the illusion of it connecting to the tabpanel
for active elements, and the illusion that inactive elements are behind the active tabpanel
.
<div class="tabs">
<div role="tablist" aria-label="Sample Tabs">
<button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1" tabindex="0">
First Tab
</button>
<button role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1">
Second Tab
</button>
<button role="tab" aria-selected="false" aria-controls="panel-3" id="tab-3" tabindex="-1">
Third Tab
</button>
</div>
<div id="panel-1" role="tabpanel" tabindex="0" aria-labelledby="tab-1">
<p>Content for the first panel</p>
</div>
<div id="panel-2" role="tabpanel" tabindex="0" aria-labelledby="tab-2" hidden>
<p>Content for the second panel</p>
</div>
<div id="panel-3" role="tabpanel" tabindex="0" aria-labelledby="tab-3" hidden>
<p>Content for the third panel</p>
</div>
</div>
.tabs {
padding: 1em;
}
[role="tablist"] {
margin-bottom: -1px;
}
[role="tab"] {
position: relative;
z-index: 1;
background: white;
border-radius: 5px 5px 0 0;
border: 1px solid grey;
border-bottom: 0;
padding: 0.2em;
}
[role="tab"][aria-selected="true"] {
z-index: 3;
}
[role="tabpanel"] {
position: relative;
padding: 0 0.5em 0.5em 0.7em;
border: 1px solid grey;
border-radius: 0 0 5px 5px;
background: white;
z-index: 2;
}
[role="tabpanel"]:focus {
border-color: orange;
outline: 1px solid orange;
}
There are two things we need to do with JavaScript: we need to change focus and tab index of our tab
elements with the right and left arrows, and we need to change the active tab
and tabpanel
when we click on a tab
.
To accomplish the first, we listen for the keydown
event on the tablist
. If the event's keyCode
is 39 for right arrow or 37 for the left arrow, we react to the event. We start by setting the tabindex
of the current tab
element to -1, making it no longer tabbable. Then, if the right arrow is being pressed, we increase our tab focus counter by one. If the counter is greater than the number of tab
elements we have, we circle back to the first tab by setting that counter to 0. If the left arrow is being pressed, we decrease our tab focus counter by one, and if it is then less than 0, we set it number of tab
elements minus one (to get to the last element). Finally, we set focus to the tab
element whose index is equal to the tab focus counter, and set its tabindex
to 0 to make it tabbable.
To handle changing the active tab
and tabpanel
, we have a function that takes in the event, gets the element that triggered the event, the triggering element's parent element, and its grandparent element. We then find all tabs with aria-selected=true
inside the parent element and sets it to false
, then sets the triggering element's aria-selected
to true
. After that, we find all tabpanel
elements in the grandparent element, make them all hidden
, and finally select the element whose id
is equal to the triggering tab
's aria-controls
and removes the hidden
attribute, making it visible.
window.addEventListener("DOMContentLoaded", () => {
const tabs = document.querySelectorAll('[role="tab"]');
const tabList = document.querySelector('[role="tablist"]');
// Add a click event handler to each tab
tabs.forEach(tab => {
tab.addEventListener("click", changeTabs);
});
// Enable arrow navigation between tabs in the tab list
let tabFocus = 0;
tabList.addEventListener("keydown", e => {
// Move right
if (e.keyCode === 39 || e.keyCode === 37) {
tabs[tabFocus].setAttribute("tabindex", -1);
if (e.keyCode === 39) {
tabFocus++;
// If we're at the end, go to the start
if (tabFocus >= tabs.length) {
tabFocus = 0;
}
// Move left
} else if (e.keyCode === 37) {
tabFocus--;
// If we're at the start, move to the end
if (tabFocus < 0) {
tabFocus = tabs.length - 1;
}
}
tabs[tabFocus].setAttribute("tabindex", 0);
tabs[tabFocus].focus();
}
});
});
function changeTabs(e) {
const target = e.target;
const parent = target.parentNode;
const grandparent = parent.parentNode;
// Remove all current selected tabs
parent
.querySelectorAll('[aria-selected="true"]')
.forEach(t => t.setAttribute("aria-selected", false));
// Set this tab as selected
target.setAttribute("aria-selected", true);
// Hide all tab panels
grandparent
.querySelectorAll('[role="tabpanel"]')
.forEach(p => p.setAttribute("hidden", true));
// Show the selected panel
grandparent.parentNode
.querySelector(`#${target.getAttribute("aria-controls")}`)
.removeAttribute("hidden");
}
Best practices
It is recommended to use a button
element with the role tab
for their built-in functional and accessible features instead, as opposed to needing to add them yourself. For controlling tab key functionality for elements with the role tab
, it is recommended to set all non-active elements to tabindex=-1
, and to set the active element to tabindex=0
.
Specifications
Specification | Status |
---|---|
Accessible Rich Internet Applications (WAI-ARIA) 1.1 The definition of 'tab' in that specification. | Recommendation |
WAI-ARIA Authoring Practices The definition of 'tabs' in that specification. | Working Draft |
Precedence order
What are the related properties, and in what order will this attribute or property be read (which property will take precedence over this one, and which property will be overwritten.
Screen reader support
TBD
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论