Using tabindex Effectively
From where I stand, tabindex
is an underutilized HTML attribute. That being
said, when used incorrectly, it can prove disastrous! Let's talk about the when
and the how of tabindex
.
Making "Non-Clickable" Elements Focusable
With JavaScript, its easy to make an element clickable. Either through DOM
manipulation or via a framework like React, making a <div>
as interactive as a
<button>
is trivially easy. Unfortunately, a <div>
will not be a part of the
document's tab order like a button
! That's where tabindex
comes in handy.
Let's say we have a <div>
that opens up a modal when clicked like so:
<div class="button">I trigger some behavior.</div>
By default, the keyboard cannot find this element, and thus, neither will screen readers be informed that the elememnt is interactive. This is a huge problem from an accessibility standpoint! This is a clear violation of the WCAG 2.1 guideline regarding keyboard accessibility.
To remedy that, add tabindex="0"
and role="button"
to inform screen
readers that the element is interactive.
<div class="button" tabindex="0" role="button">I trigger some behavior.</div>
Ta-dah! The element can now receive keyboard focus whenever the user hits the tab key.
Making Elements Programmatically Focusable
With JavaScript, moving focus to an element is often required in order to help improve user experience, and frequently a must-have when making complex interactions accessible for all users. THat being said, focus can't be moved to just any old element. Consider the following example:
<div class="alert alert--error" id="my-alert">Warning! Invalid password.</div>
Let's say we want to move focus to this alert:
document.querySelector('#my-alert').focus()
Unfortunately this won't work! We need to first add some value for tabindex
.
So let's try tabindex="0"
like before:
<div class="alert alert--error" id="my-alert" tabindex="0">
Warning! Invalid password.
</div>
Woohoo! This works. Sort of.
Unfortunately, what we've done is introduced the alert in to the keyboard tab order. As a user tabs through interactive elements, they then encounter the alert, only to find that it isn't actually an interactive element.
Negative tabindex to the Rescue!
This is when leveraging tabindex="-1"
comes in to play. This makes the element
both programmatically focusable and keeps the element outside of the tab order
of the document.
So, we end up with:
<div class="alert alert--error" id="my-alert" tabindex="-1">
Warning! Invalid password.
</div>
Other Values for tabindex
Other, positive values are technically valid for use with tabindex
, however,
these should pretty much never ever be used. By supplying positive values for
tabindex
, the "natural" tab order of the page can be modified, unfortunately
resulting in accidental keyboard tab traps, a big
accessibility no-no.
Wrapping Up
tabindex
is a critically important attribute, particularly when working to
build a page that is usable for keyboard-only users and our friendly
neighborhood power user.
To summarize:
- Add
tabindex="0"
to elements that are typically non-interactive that have been made interactive by JavaScript - Add
tabindex="-1"
to elements that need to receive focus programmatically but should not be a part of the keyboard order of the document and - Never ever use a positive value for
tabindex
About Me
I’m a frontend engineering manager working for Truist Financial currently based in in Columbia, Maryland.
I’m driven to spearhead, design, and build accessible design systems and web applications with a great underlying developer experience in mind.