Fun with the tabindex attribute

The tabIndex attribute can be used to allow nearly any element to be put into the tab order or receive focus programmatically. This has been implemented in Internet Explorer starting with version 5, Firefox starting with version 1.5 and is currently being implemented in Opera 9.5.

Being able to set focus to any element on the page is important for accessibility in order to implement full keyboard navigation. Elements that represent the intial interaction with a user interface component

can be but into the tab order. Other elements which are part of a particular user interface component can be interacted with via other key combinations. The keystroke interaction and identification of the user interface components to assistive technologies depends upon being able to set focus to these elements.

How Focus and tab key navigation work

  • Normally only input and anchor elements are put into the tab order of a page by default.
  • Setting a tabIndex attribute of 0 onto an element will put it into the tab order of the page and allow it to receive focus via the keyboard.
  • Setting a tabIndex of -1 on an element will allow the element to receive focus programmatically. For input and anchor elements, setting tabIndex of -1 will remove the element from the tab order and allow focus to only be set programmatically.
  • Setting a tabIndex of >0 onto an element will put that element sequentially into the tab order based on the tabIndex value. Elements with a positive tab index are put into

    the tab order before other elements with a tabIndex of 0 or which are in the tab order by default.

There are different behaviors for the tabIndex attribute and capitalization of the I makes a difference in how the attribute is interpretted in html and xhtml.

After testing different combinations of setting and querying the tabindex attribute, a set of best practices is outlined below followed by a table listing the results of each test.

Using tabIndex across browser and content type

  1. Always use tabindex with lowercase i in markup. See row 1 in table below.
  2. Use tabIndex with uppercase I when setting in script via element.tabIndex. See row 4 in table below.
  3. Check browser and/or content-type when setting in script via element.setAttribute()
    • if is IE or content-type is text/html – set via elem.setAttribute(tabIndex) uppercase. See row 6 in table below.
    • if is content-type application/xhtml+xml or not IE 6 or 7 – set via elem.setAttribute(tabindex) lowercase. See row 7 in table below
  4. Use lowercase when querying a value using getAttribute(tabindex) that was set in markup as lowercase. See row 9 in table below.
  5. Use lowercase when querying a value using getAttribute(tabindex) that was set directly on element using element.tabIndex uppercase. See row 15 in table below.

    Setting tabIndex directly on the element using element.tabIndex avoids having to check browser or content type when getting the value.

  6. If the rules above have been followed, use lowercase when querying a value using hasAttribute(tabindex) where available. See rows 25, 31 and 33 in table below.

Simplified Rules

  • use tabindex lowercase to set in markup
  • use element.tabIndex with uppercase I to set in script
  • query via getAttribute(tabindex) lowercase

TabIndex testing results

The following table shows the results of testing on Windows with Internet Explorer versions 6 and 7, Firefox 2, Firefox 3 (3.0a9pre dated 2007/09/27) and Opera 9.5 alpha (build 9500 dated 2007/09/04).

IE 6 and 7 where tested using HTML 4.01 strict and transitional. Firefox 2 and 3 as well as Opera were tested with HTML 4.01 strict and transitional as well as with XHTML 1.0 strict

served with content-type of application/xhtml+xml. Unless otherwise noted, a div was used as the test element.

 IE 6   IE 7  FF 2 HTML FF 3 HTML Opera 9.5alpha HTML FF 2 XHTML FF 3 XHTML Opera 9.5alpha XHTML
1 tabindex set in markup (lowercase) yes yes yes yes yes yes yes yes
2 tabIndex set in markup (uppercase) yes yes yes yes yes no no no
3 tabindex set via elem.tabindex (lowercase) no no no no no no no no
4 tabIndex set via elem.tabIndex (uppercase) yes yes yes yes yes yes yes yes
5 tabindex set via setAttribute(tabindex) (lowercase) no no yes yes yes yes yes yes
6 tabIndex set via setAttribute(tabIndex) (uppercase) yes yes yes yes yes no no no
7 query elem.tabIndex uppercase when set as 0 in markup as lowercase 0 0 0 0 0 0 0 0
8 query elem.tabIndex uppercase when set as 0 in markup as uppercase 0 0 0 0 0 -1 -1 -1
9 query getAttribute(tabindex) lowercase when set as 0 in markup as lowercase 0 0 0 0 0 0 0 0
10 query getAttribute(tabIndex) uppercase when set as 0 in markup as lowercase 0 0 0 0 0 null null null
11 query getAttribute(tabindex) lowercase when set as 0 in markup as uppercase 0 0 0 0 0 null null null
12 query getAttribute(tabIndex) uppercase when set as 0 in markup as uppercase 0 0 0 0 0 0 1 0 1 0 1
13 query getAttribute(tabindex) lowercase when set via elem.tabindex lowercase 0 0 null null null null null null
14 query getAttribute(tabIndex) uppercase when set via elem.tabindex lowercase 0 0 null null null null null null
15 query getAttribute(tabindex) lowercase when set via elem.tabIndex uppercase 0 0 0 0 0 0 0 0
16 query getAttribute(tabindex) uppercase when set via elem.tabIndexuppercase 0 0 0 0 0 null null null
17 query getAttribute(tabindex) lowercase when set via setAttribute as lowercase 0 2 0 2 0 0 0 0 0 0
18 query getAttribute(tabIndex) uppercase when set via setAttribute as lowercase 0 0 0 0 0 null null null
18 query getAttribute(tabindex) lowercase when set via setAttribute as uppercase 0 0 0 0 0 null null null
20 query getAttribute(tabIndex) uppercase when set via setAttribute as uppercase 0 0 0 0 0 0 3 0 3 0 3
21 query elem.tabIndex uppercase when it has not been set in markup 0 0 -1 -1 -1 -1 -1 -1
22 query getAttribute(tabIndex) upper or lowercase when it has not been set in markup 0 0 null null null null null null
23 query elem.tabIndex from <a> with no explict value set 0 0 0 0 0 0 0 0
24 query getAttribute(tabIndex) upper or lowercase from <a> with no explict value set 0 0 null null null null null null
25 query hasAttribute(tabindex) lowercase when set in markup as lowercase NA NA true true true true true true
26 query hasAttribute(tabIndex) uppercase when set inmarkup as lowercase NA NA true true true false false false
27 query hasAttribute(tabindex) lowercase when set in markup as uppercase NA NA true true true false false false
28 query hasAttribute(tabIndex) uppercase when set in markup as uppercase NA NA true true true true 1 true 1 true 1
29 query hasAttribute(tabindex) lowercase when set via elem.tabindex lowercase NA NA false false false false false false
30 query hasAttribute(tabIndex) uppercase when set via elem.tabindex lowercase NA NA false false false false false false
31 query hasAttribute(tabindex) lowercase when set via elem.tabIndex uppercase NA NA true true true true true true
32 query hasAttribute(tabindex) uppercase when set via elem.tabIndexuppercase NA NA true true true false false false
33 query hasAttribute(tabindex) lowercase when set via setAttribute as lowercase NA NA true true true true true true
34 query hasAttribute(tabIndex) uppercase when set via setAttribute as lowercase NA NA true true true false false false
35 query hasAttribute(tabindex) lowercase when set via setAttribute as uppercase NA NA true true true false false false
36 query hasAttribute(tabIndex) uppercase when set via setAttribute as uppercase NA NA true true true true true true
37 query hasAttribute(tabIndex) upper or lowercase from <a> with no explict value set NA NA false false false false false false

Table Notes:

  1. Setting in markup as uppercase tabIndex does not work in XHTML to allow focus to element.
  2. setAttribute(tabindex) lowercase does not work in IE to allow focus to element.
  3. setAttribute(tabIndex) uppercase does not work in XHTML to allow focus to element.

About Becka11y

Web Accessibility Consultant with 30+ years in the software industry and 12+ years of direct accessibility innovation.

One comment:

Leave a Reply

Your email address will not be published. Required fields are marked *