I’ve never implemented this, but I’ve looked into a similar problem, and here’s what I would try.
Referencing the jQuery implementation, you must:
- Listen for Tab and Shift+Tab
- Know which elements are tab-able
- Understand how tab order works
1. Listen for Tab and Shift+Tab
Listening for Tab and Shift+Tab are probably well-covered elsewhere on the web, so I’ll skip that part.
2. Know which elements are tab-able
Knowing which elements are tab-able is trickier. Basically, an element is tab-able if it is focusable and does not have the attribute tabindex="-1" set. So then we must ask which elements are focusable. The following elements are focusable:
input,select,textarea,button, andobjectelements that aren’t disabled.aandareaelements that have anhrefor have a numerical value fortabindexset.- any element that has a numerical value for
tabindexset.
Furthermore, an element is focusable only if:
- None of its ancestors are
display: none. - The computed value of
visibilityisvisible. This means that the nearest ancestor to havevisibilityset must have a value ofvisible. If no ancestor hasvisibilityset, then the computed value isvisible.
More details are in another Stack Overflow answer.
3. Understand how tab order works
The tab order of elements in a document is controlled by the tabindex attribute. If no value is set, the tabindex is effectively 0.
The tabindex order for the document is: 1, 2, 3, …, 0.
Initially, when the body element (or no element) has focus, the first element in the tab order is the lowest non-zero tabindex. If multiple elements have the same tabindex, you then go in document order until you reach the last element with that tabindex. Then you move to the next lowest tabindex and the process continues. Finally, finish with those elements with a zero (or empty) tabindex.