Standard HTML elements such as <button>
or <input>
have keyboard accessibility
built in, and should be used whenever possible. However, if you need to build
custom interactive elements, you can create the expected user behavior by
adding tabindex
.
Only add tabindex
to content that is interactive. Even if content is
important, such as a key image, screen reader users can understand it without
adding focus.
What is tabindex?
In the occasion you need to modify the default tab order provided by built-in
elements, you can use the tabindex
HTML attribute to explicitly set an
element's tab position.
tabindex
can be applied to any element, though it should only be applied to
interactive elements, and takes a range of integer values. With
tabindex
, you can specify an explicit order for focusable page elements,
insert an otherwise unfocusable element into the tab order, and remove elements
from the tab order. For example:
tabindex="0"
: Inserts an element into the natural tab order. The element can
be focused by pressing Tab, and the element can be focused by calling
its focus()
method.
tabindex="-1"
: Removes an element from the natural tab order, but the element
can still be focused by calling its focus()
method
tabindex="5"
: Any tabindex greater than 0
brings that element to the front
of the natural tab order. If there are multiple elements with a tabindex greater
than 0
, the tab order starts from the lowest value that is greater than zero
and works its way up. Using a tabindex greater than 0
is considered an
anti-pattern.
Ensure controls are keyboard accessible
A tool like Lighthouse is great at automatically detecting certain accessibility issues, however, some testing still must be manually done by a human.
Try pressing the Tab
key to navigate through your site. Are you able to reach
all the interactive controls on the page? If not, you may need to use
tabindex
to improve the focusability of those controls.
Manage focus at the page level
Sometimes, tabindex
helps create seamless user experience. For example,
if you build a robust single page with different content sections, where some
content is hidden at different points in the page load. This could mean
navigation links change the visible content, without a page refresh.
In this case, identify the selected content area and give it a tabindex
of
-1
and call its focus
method. This ensures the content doesn't appear in
the natural tab order. This technique, called managing focus, keeps the
user's perceived context in sync with the site's visual content.
Manage focus in components
In some cases, you must also manage focus at the control level, such as with Custom Elements.
Knowing which keyboard behaviors to implement can be difficult. The Accessible Rich Internet Applications (ARIA) Authoring Practices guide lists types of components and what kinds of keyboard actions they support.
Insert an element into the tab order
Insert an element into the natural tab order using tabindex="0"
. For example:
<div tabindex="0">Focus me with the TAB key</div>
To focus an element, press the Tab
key or call the element's focus()
method.
Remove an element from the tab order
Remove an element using tabindex="-1"
. For example:
<button tabindex="-1">Can't reach me with the TAB key!</button>
This removes an element from the natural tab order, but the element can still be
focused by calling its focus()
method.
Applying tabindex="-1"
to an element doesn't affect its children;
if they're in the tab order naturally or because of a tabindex
value,
they'll remain in the tab order.
To remove an element and all its children from the tab order, consider using
the WICG's inert
polyfill.
The polyfill emulates the behavior of a proposed inert
attribute,
which prevents elements from being selected or read by assistive technologies.
Avoid tabindex > 0
Any tabindex
greater than 0 jumps the element to the front of the natural tab
order. If there are multiple elements with a tabindex
greater than 0, the tab
order starts from the lowest value greater than zero and works its way up.
Using a tabindex
greater than 0 is considered an anti-pattern because
screen readers navigate the page in DOM order, not tab order. If you need an
element to come sooner in the tab order, it should be moved to an earlier spot
in the DOM.
With Lighthouse, you can identify elements with a tabindex
> 0. Run the
Accessibility Audit (Lighthouse > Options > Accessibility) and look for the
results of the "No element has a [tabindex]
value greater than 0" audit.
Use "roving tabindex
"
If you're building a complex component, you may need to add additional keyboard
support beyond focus. When possible, use the built-in select
element. It's
focusable and allows for arrow keys to expose additional selectable
options.
To implement similar functions in your own components, you can use a technique known
as "roving tabindex
". Roving tabindex works by setting tabindex
to -1 for
all children except the currently-active one. The component then uses a keyboard
event listener to determine which key the user has pressed.
When this happens, the component sets the previously focused child's tabindex
to -1, sets the to-be-focused child's tabindex
to 0, and calls the focus()
method on it.
Before
<div role="toolbar">
<button tabindex="-1">Undo</button>
<button tabindex="0">Redo</button>
<button tabindex="-1">Cut</button>
</div>
After
<div role="toolbar">
<button tabindex="-1">Undo</button>
<button tabindex="-1">Redo</button>
<button tabindex="0">Cut</button>
</div>
Keyboard access recipes
If you're unsure what level of keyboard support your custom components might need, you can refer to the ARIA Authoring Practices 1.1. This guide lists common UI patterns and identifies which keys your components should support.