Website problems
Positive tabindex values
The tab sequence normally follows the order of elements in the document, which usually matches the visual order. A positive tabindex value removes an element from that sequence and places it ahead of everything using the default. The effect is not local: a single attribute inside one component changes the focus order of every page that component appears on, and two components each using positive values interleave in an order neither author intended.
How the ordering actually works
Elements with a positive value are visited first, in ascending numeric order, regardless of where they appear in the document.
Only then does focus move to elements with a value of zero or with the implicit default, in document order.
So an element with a value of one is the first thing focused on the page, before the skip link and before the navigation.
A value of negative one removes an element from the sequence while leaving it focusable by script, which is legitimate and unrelated.
Zero puts an element into the normal sequence at its document position, which is what a custom control needs and is also legitimate.
Why it does not compose
Two components each using positive values share one numeric space across the whole page.
A component using one, two and three, placed alongside one using ten, twenty and thirty, produces an order neither author designed.
Adding a third component means renumbering, which means editing components that were working.
Any component library using them is therefore unusable alongside another that does, which is a strong argument against ever shipping them.
This is the property that makes the attribute unfixable rather than merely awkward.
What a keyboard user experiences
Focus jumps to somewhere unrelated to where they are looking, then eventually returns to the top of the page.
The visual order and the focus order disagree, which makes the page impossible to predict.
A skip link, if present, is no longer the first focusable element, so its whole purpose is defeated.
Someone using a screen reader gets the same disorder with no visual context to recover from.
Which is why the criterion about focus order existing in a meaningful sequence is the one this fails.
How to fix it
Remove every positive value and replace it with zero where the element needs to be focusable and is not natively.
Reorder the markup so the document order matches the visual order, which is what the tab sequence should follow anyway.
Where visual order is produced by layout — a grid or flex ordering that differs from the source — change the source rather than the focus.
For a modal or a component that must be reached first, move focus into it with script when it opens rather than reordering the page.
Check the result by tabbing through the page, which takes a minute and is the only complete test.
Where the attribute comes from
An attempt to make one form field focus first, applied without realising the effect is page-wide.
A carried-over pattern from older codebases, where it was more common advice.
A component library that shipped it, which is rare now and still present in long-lived dependencies.
A generated interface where a builder assigns sequential values to every field.
In every case the intent was local and the effect is not, which is the whole of the problem.
How to check it yourself
Search the served HTML for a tabindex attribute with a value greater than zero.
Tab through the page from the address bar and watch where focus goes first — anything other than the skip link or the first navigation item is a signal.
Check pages built from different templates, since the attribute usually lives in one component.
Check the live DOM as well as the source, since a script can add the attribute after load.
Confirm the visual order and the focus order agree once the values are removed.
How VeriFixScan detects it
`accessibility.tabindex` reports the tab order including positive values, which is this problem directly.
`accessibility.keyboard_navigation` reports the structures that determine whether the page can be operated from a keyboard at all.
`accessibility.skip_link` reports whether a skip link exists and behaves, which a positive value defeats.
`accessibility.interactive_elements` reports elements made interactive without the semantics that make them reachable, which is the neighbouring defect.
Values applied by script after load are outside the served markup and are not observed.
Frequently asked questions
- Is tabindex="0" a problem too?
- No. Zero puts an element into the normal sequence at its document position, which is exactly what a custom control needs. Only positive values reorder the page.
- What about tabindex="-1"?
- Also fine. It removes an element from the tab sequence while leaving it focusable by script, which is how focus is moved into a dialog when it opens.
- I need one field focused first. What should I do?
- Move focus to it with script on load, or reorder the markup. A positive value achieves it by reordering every other focusable element on the page.
Sources
Related
VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.
Scan a website