Back in November, 2007 I blogged my results of testing the tabindex attribute in several browsers. I recently retested with the latest versions of the browsers and included Safari 4. Luckily the recommended methods for working with the tabindex attribute do not change. Here is the updated version:
All you never wanted to know about tabindex
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, Opera 9.5 and Safari 4.
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
- Always use tabindex with lowercase i in markup. See row 1 in table below.
- Use tabIndex with uppercase I when setting in script via element.tabIndex. See row 4 in table below.
- 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
- Use lowercase when querying a value using getAttribute(tabindex) that was set in markup as lowercase. See row 9 in table below.
- 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. - 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, 7, and 8, Firefox 2.0.0.20, Firefox 3.0.1, Firefox 3.5, Opera 9.64 and Safari 4.
IE 6, 7, 8 where tested using HTML 4.01 strict. Firefox 2, 3, 3.5 as well as Opera and Safari were tested with HTML 4.01 strict 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/7 | IE 8 HTML | FF 2/3/3.5, Opera 9.64, Safari 4 HTML | FF 2/3/3.5, Opera 9.64, Safari 4 XHTML | ||
---|---|---|---|---|---|
1 | tabindex set in markup (lowercase) | yes | yes | yes | yes |
2 | tabIndex set in markup (uppercase) | yes | yes | yes | no |
3 | tabindex set via elem.tabindex (lowercase) | no | no | no | no |
4 | tabIndex set via elem.tabIndex (uppercase) | yes | yes | yes | yes |
5 | tabindex set via setAttribute(tabindex) (lowercase) | no | yes | yes | yes |
6 | tabIndex set via setAttribute(tabIndex) (uppercase) | yes | yes | yes | no |
7 | query elem.tabIndex uppercase when set as 0 in markup as lowercase | 0 | 0 | 0 | 0 |
8 | query elem.tabIndex uppercase when set as 0 in markup as uppercase | 0 | 0 | 0 | -1 |
9 | query getAttribute(tabindex) lowercase when set as 0 in markup as lowercase | 0 | 0 | 0 | 0 |
10 | query getAttribute(tabIndex) uppercase when set as 0 in markup as lowercase | 0 | 0 | 0 | null |
11 | query getAttribute(tabindex) lowercase when set as 0 in markup as uppercase | 0 | 0 | 0 | null |
12 | query getAttribute(tabIndex) uppercase when set as 0 in markup as uppercase | 0 | 0 | 0 | 0 1 |
13 | query getAttribute(tabindex) lowercase when set via elem.tabindex lowercase | 0 | null | null | null |
14 | query getAttribute(tabIndex) uppercase when set via elem.tabindex lowercase | 0 | null | null | null |
15 | query getAttribute(tabindex) lowercase when set via elem.tabIndex uppercase | 0 | 0 | 0 | 0 |
16 | query getAttribute(tabIndex) uppercase when set via elem.tabIndex uppercase | 0 | 0 | 0 | null |
17 | query getAttribute(tabindex) lowercase when set via setAttribute as lowercase | 0 2 | 0 | 0 | 0 |
18 | query getAttribute(tabIndex) uppercase when set via setAttribute as lowercase | 0 | 0 | 0 | null |
19 | query getAttribute(tabindex) lowercase when set via setAttribute as uppercase | 0 | 0 | 0 | null |
20 | query getAttribute(tabIndex) uppercase when set via setAttribute as uppercase | 0 | 0 | 0 | 0 3 |
21 | query elem.tabIndex uppercase when it has not been set in markup | 0 | 0 | -1 | -1 |
22 | query getAttribute(tabIndex) upper or lowercase when it has not been set in markup | 0 | null | null | null |
23 | query elem.tabIndex from <a> with no explict value set | 0 | 0 | 0 | 0 |
24 | query getAttribute(tabIndex) upper or lowercase from <a> with no explict value set | 0 | null | null | null |
25 | query hasAttribute(tabindex) lowercase when set in markup as lowercase | NA | true | true | true |
26 | query hasAttribute(tabIndex) uppercase when set inmarkup as lowercase | NA | true | true | false |
27 | query hasAttribute(tabindex) lowercase when set in markup as uppercase | NA | true | true | false |
28 | query hasAttribute(tabIndex) uppercase when set in markup as uppercase | NA | true | true | true 1 |
29 | query hasAttribute(tabindex) lowercase when set via elem.tabindex lowercase | NA | false | false | false |
30 | query hasAttribute(tabIndex) uppercase when set via elem.tabindex lowercase | NA | false | false | false |
31 | query hasAttribute(tabindex) lowercase when set via elem.tabIndex uppercase | NA | true | true | true |
32 | query hasAttribute(tabIndex) uppercase when set via elem.tabIndex uppercase | NA | true | true | false |
33 | query hasAttribute(tabindex) lowercase when set via setAttribute as lowercase | NA | true | true | true |
34 | query hasAttribute(tabIndex) uppercase when set via setAttribute as lowercase | NA | true | true | false |
35 | query hasAttribute(tabindex) lowercase when set via setAttribute as uppercase | NA | true | true | false |
36 | query hasAttribute(tabIndex) uppercase when set via setAttribute as uppercase | NA | true | true | true |
37 | query hasAttribute(tabIndex) upper or lowercase from <a> with no explict value set | NA | false | false | false |
Table Notes:
- Setting in markup as uppercase tabIndex does not work in XHTML to allow focus to element.
- setAttribute(tabindex) lowercase does not work in IE to allow focus to element.
- setAttribute(tabIndex) uppercase does not work in XHTML to allow focus to element.
One comment: