Use the tabindex
attribute
Table of Contents
tabindex
is a global attribute that allows an HTML element to receive focus. It needs a value of zero or a negative number in order to work in an accessible way.
When tabindex
’s value is set to zero or a positive number, the element can be navigated to via the keyboard’s Tab key. When it is set to a negative number, its element can be programmatically focused via JavaScript.
Common mistakes
Unfortunately, the tabindex
attribute is often misunderstood and consequently misused. Following are some common examples of tabindex
use that have a negative impact on accessibility:
Using a positive tabindex
value
Using tabindex
with a value of 1
, 2
, 3
, etc. places the element the tabindex
is applied first in the keyboard tabbing order. This can create a confusing experience for anyone who relies on the keyboard’s Tab key to navigate.
Setting a manual tab order
You don’t need to manually set tab order for every page or view on a website or web app. Not only is this extra, unnecessary work that is difficult to maintain, it may deviate from someone’s expected or desired way to navigate. This results an annoying, confusing, and potentially inaccessible experience.
Instead, use appropriate interactive elements (a
for links, button
for buttons, etc.) and put them in the reading order of the document. Interactive elements come with native browser behavior already built in that allows them to be navigated to via Tab without the need for a tabindex
declaration.
Making non-interactive elements focusable
There is a myth that applying tabindex="0"
to non-interactive elements (paragraphs, headings, lists, etc.) helps “improve” accessibility by providing a way for a person who uses a screen reader to focus on all the content present in a webpage or web app. Unfortunately, this well-intentioned idea actually does not create a good assistive technology experience.
In the same way that you don’t need to add a tabindex
attribute declaration to native interactive elements, you also don’t need to add a tabindex
attribute to non-interactive elements for them to work with assistive technologies.
The reason for this is that assistive technologies such as screen readers have other, expected ways of navigating through, and consuming this content. Because of this, adding a tabindex
attribute to non-interactive elements creates a few problems. It:
- Adds confusion about what is and what is not actually interactive, especially if you cannot see the screen.
- Requires extra work for people using keyboards to navigate (and in particular, people who use keyboards who are not using assistive technologies), especially those who have have a motor control disability.
- May not announce the element’s name and role, which creates additional confusion about what the element is, how it is supposed to work, and whether or not it has been coded properly.
tabindex
declared on a non-interactive element nested inside of an interactive element
You do not need to declare tabindex
on a child element, provided its parent element is an interactive element. An example of this would be a span
element nested inside of a button
:
The presence of the tabindex
attribute in this code example would affect the order of interactive elements in an illogical way. This creates an annoying and potentially confusing experience for people using keyboards or assistive technology.
Acceptable uses for tabindex
Following are some of the more common cases where you do need to use tabindex
. In these scenarios it enables the content to be accessible.
Interactive JavaScript widgets and charts
Declarations of tabindex="-1"
can sometimes be found on interactive widgets and components that manage focus internally, such as comboboxes or trees, as it allows JavaScript to focus on the element via the focus()
method.
Scrollable overflow containers
tabindex="0"
should be applied to any non-interactive element that has had CSS’ overflow
property applied to it. This will allow people using a keyboard to navigate to, and scroll around the overflowed content.
You will also need to provide:
- A label that concisely describes the contents placed within the non-interactive element. The label can either be provided by:
- An
id
/aria-labelledby
association if it has a visible heading, or - An
aria-label
, if not.
- An
- A way to specify what the content contains semantically. This can be provided by:
- An applicable sectioning element, or
- A Landmark Role if the content is important enough that people need a quick and easy way to return to it.
- A
group
role can also be used if there isn’t a need for quick access.
<div
aria-labelledby="terms-of-service"
role="group"
tabindex="0"
style="overflow: auto; height: 15rem;">
<h2 id="terms-of-service">Terms of Service</h2>
…
</div>
This satisfies WCAG criterion 4.1.2: Name, Role, Value. It allows people to scroll using a keyboard, as well as providing an indication on why they should scroll, and what content they can expect to find within.
When there is not an applicable HTML element
Interactive controls that don’t have a relevant HTML element need a declaration of tabindex="0"
. An example of this would be a listbox, a widget that “presents a list of options and allows a user to select one or more of them.”
Hopefully this provides enough information to treat tabindex
in a responsible, accessible way.
Thank you to Sarah Higley and Patrick Lauke for their feedback.
Further reading
- Keyboard Accessibility WebAIM
- Web Fundamentals: Using tabindex Google Developers
- Using the tabindex attribute The TPGi
- Don’t Use Tabindex Greater than 0 Adrian Roselli
- Tabindex: it rarely pays to be positive Scott O'Hara
- Short note on improving usability of scrollable regions The TPGi
- The difference between keyboard and screen reader navigation Léonie Watson