Don’t Use Tabindex Greater than 0

Animated GIF
Animated GIF showing the tab order on a page using the default Re-CAPTCHA, which sets a tabindex, forcing a keyboard user through six tab-stops to get to the Skip to content link.

Tabindex had the potential to be a useful attribute. A developer could set the order in which focus is moved on a page as a user tabs through the form (or links, or content). It became a stop-gap for forms and pages that relied too heavily on absolute positioning and didn’t flow naturally. The problem is that it is often set by developers who don’t have any idea of what the user expects.

This mis-use has effectively guaranteed that using tabindex values greater than zero is a bad idea. If, as a developer, you have to use tabindex on a form, then the page itself probably isn’t laid out well and will only confuse keyboard users and, more importantly, users of assistive technology.

Browsers take any element with a positive tabindex value and promote it to the front of the pack for tabbing through the page. Only after a browser gets through all elements with a tabindex does it then fall back to source order. It doesn’t matter if your tabindex is one million, it will still trump everything on the page that doesn’t have a tabindex.

This is such a well-known issue that the W3C HTML Working Group is working on new language to deprecate values greater than zero. There is even a bug filed against the HTML specification to that effect.

For more detail I encourage you to read Léonie Watson’s piece, Using the tabindex attribute.

Tabindex Best Practices

Here are some tips to use tabindex properly.

tabindex="-1"

Setting tabindex="-1" allows you to set an element’s focus with script, but does not put it in the tab order of the page. This is handy when you need to move focus to something you have updated via script or outside of user action.

tabindex="0"

Setting tabindex="0" will take an element and make it focusable. It doesn’t set the element’s position in the tab order, it just allows a user to focus the element in the order determined by its location with the DOM.

tabindex="1" (or any value > 0)

Do not set a tabindex="1" or any value greater than zero (or any positive value).

The Example

The example in the animated GIF above is unfortunate in that the site developers themselves don’t set a tabindex (I found this at User Experience Impossible: The Line Between Accessibility and Usability on the GSA‘s DigitalGov site). Instead, for reasons I cannot explain, they use a CAPTCHA on the comment form. The implementation they chose, however, inserts its own tabindex values.

This means that as the user starts tabbing through the page, he or she is first sent to the text entry field on the CAPTCHA in the comments section.

Even as a sighted mouse-user, I was confused how I got there as I tabbed into the page. It takes five more tabs to get to the link that allows the user to skip to the content (which appears first on the page).

This also creates a problem for a user who is filling out the comment form, as tabbing from the Name and then Email fields puts the user on the privacy link for the CAPTCHA, but not into the field where he or she can type the text to submit the form. Some users may never know there is a CAPTCHA there depending on how they got to the comment form.

Paul J. Adam shows the offending code in a tweet, which I will steal and display here since I’m too lazy to screen-capture it:

I don’t want to beat up the DigitalGove folks, but this is a great example of how a perfectly functional page (regardless of how I feel about the hover versus focus styles) can be ruined by not testing it after adding third-party widgets.

Bonus: Don’t Use CAPTCHA

There’s a lot written about this. I’ll just link to this from the W3C: Inaccessibility of CAPTCHA

Update: November 19, 2014 at 1:25pm

My notes on reporting this to DigitalGov

I still haven’t heard back from the folks at DigitalGov on Twitter, but Jonathan Rubin from the GSA responded (though he did ping an account that hasn’t tweeted in a month), I just haven’t heard any more from him. I’ve also left a comment (pending moderation) on the site itself.

I discovered while trying to leave a comment that the ReCAPTCHA is served via HTTP while the page is served via HTTPS. One of my browsers (IE) blocks it by default because it’s an insecure element on a secure page. That means I won’t experience the tabbing problem, but it also means that I cannot leave a comment as the form silently breaks without the ReCAPTCHA. I’ve left a comment for that as well (but I didn’t see a preview and I got no error messages, so, yeah).

Here’s the rub — I don’t want people beating up the DigitalGov team. That these folks have put forth such a good effort but fallen down on one issue is not uncommon. We all do that. I do it (last week Karl Groves discovered a CAPTCHA on this blog that I never saw). That I found it on a post about accessibility is unfortunate, but it also means the DigitalGov team needs to be more responsive when provided with clear technical solutions and learn to test after each feature addition. Like all the rest of us who work in or near accessibility.

Update: November 19, 2014 at 6:25pm

Follow-up notes on reporting this

The comments I posted on the DigitalGov page are still in moderation queue, even though comments posted well after mine have been approved. You can see them still in moderation in the screen capture.

Given my suspicion that they won’t be posted (since I’ve heard nothing back from the initial conversation with the Twitter account), I’ll post the comments here. The first was a reply to a site admin following up on a comment from another user noting that the keyboard navigation of the page is broken. My second comment is a follow-up.

Screen shot of comments.
The content of my comments is in the page content.

The First Comment

Response

November 19, 2014 at 12:44 PM

The ReCAPTCHA on this page uses a tabindex value. Since browsers honor tabindex values before falling to source order in the DOM, the very first (through fifth) tab stop on the page is the CAPTCHA. It takes six presses of the tab key to get to the “Skip Navigation” link. That’s the issue I suspect TRUEAXGUY is referencing.

I’ve mentioned this issue to DigitalGov on Twitter (https://twitter.com/ aardrian/status/ 534751243491901440), heard from Jonathan Rubin of the GSA on Twitter (https://twitter.com/ jonathan_rubin/status/ 534788879518539776), and used it as motivation on writing a post about tabindex best practices for accessibility: /2014/11/dont-use-tabindex-greater-than-0.html

As I’ve said before, I am happy to help, but the easiest fix is to remove ReCAPTCHA or, failing that, go to line 449 of this page (I don’t know where you call it in your pre-rendered code) and remove this: tabindex: 4 (making sure to also remove the comma from the line before it so the JavaScript doesn’t break).

The Second Comment

Response

November 19, 2014 at 1:24 PM

Also, the ReCAPTCHA is blocked by one of my browsers because it’s served as HTTP instead of HTTPS, while the page itself is served as HTTP. This means some users may never even be able to comment (no error messages are displayed on submission, it just silently fails).

Since you have moderation enabled, and since CAPTCHA is already a proven accessibility barrier, and since it’s messing with keyboard navigation, I strongly suggest you remove ReCAPTCHA altogether.

Update: December 3, 2014

Google replacing reCAPTCHA

Even Google wants to replace its ReCAPTCHA, acknowledging that it is clunky and ineffective:

Update: December 6, 2014

I gathered accessibility notes on the new reCAPTCHA from around the web and posted them: ReCAPTCHA Reboot

Update: October 23, 2016

Update: May 29, 2019

Scott O’Hara has identified an interesting aspect of Shadow DOM and tabindex:

[…P]ositive tabindex values on elements within the Shadow DOM, do not have an impact on the light DOM’s document tabbing order.

This does not mean it is ok to use positive values. It simply means Shadow DOM lives more in the shadows than I thought.

Update: July 3, 2024

I collapsed a bunch of old and irrelevant sections above and hid the opening animated GIF, without any effort to address styles when expanded. I can do that in my rebuild.

This update concerns some content on Google’s web.dev site that a junior dev asked me to explain because it was counter to the advice I offer in this article from 10 years ago.

The first is Modify DOM order with tabindex, whose very title suggests the impossible. You cannot re-order the DOM with the tabindex attribute. But this nugget stood out to me:

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.

The strongest warning against positive tabindex values in the entire piece is anti-pattern. The only WCAG warning in the article is about keyboard traps in modals, not focus order concerns. For an article released in June 2024 (last month), this is a huge disappointment, especially since I know it confused someone who needed good information to do their job.

The second web.dev article is Accessibility for web developers from February (5 months ago). It includes this nugget:

  • A tabindex value greater than 0 places the element in a manual tab order. All elements in the page with a positive tabindex value are visited in numerical order, before elements in the natural tab order.

This one contains no warning but instead can be taken as guidance to force something to the top of the tab-stack (I made that up) with no consideration for focus order nor meaningful sequence.

While I have mostly shied away from filing issues on Google’s own content (because it’s free labor that they also ignore for years), in this case I need to show the junior dev this is an issue and let them see how Google does or does not address it.

6 Comments

Reply

[…] makes extensive used of the tabindex attribute, generally a bad idea if the value is greater than 0. Thanks to this, I am immediately brought to the From field to book […]

Reply

[…] makes extensive used of the tabindex attribute, generally a bad idea149 if the value is greater than 0. Thanks to this, I am immediately brought to the From field to […]

Reply

How can we then change the tab order ??????

In response to Nick. Reply

By changing the order of the HTML on the page. Tab order should follow DOM order, so just put the HTML in the order you want people to tab through it.

Reply

How can we handle the diferent components, Like an angular app that has a lot of diferent componentes with inputs that are isolated between them? How do i make it a logical tab?

Daniela Trinchero; . Permalink
In response to Daniela Trinchero. Reply

Angular itself should not impact this. As long as the DOM order makes sense, just do not set the tabindex (assuming you are using native controls). If you have to build <div>s-as-buttons, then a tabindex="0" will be the same as not setting a specific order.

If your tabbing order from the DOM does not make sense, then you need to restructure your page. That means the reading order is probably broken as well.

Leave a Comment or Response

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>