squirrelscan
GitHub

Positive tabindex and why it breaks the tab order

tabindex=1 pulls an element to the front of the tab order for the entire page. squirrel flags every positive value on every page.

What tabindex does

tabindex="0" puts an element into the tab order at its position in the document. tabindex="-1" takes it out of the tab order while leaving it focusable from script, which is what a modal’s container or a skip link’s target needs.

A positive value creates a second, earlier sequence. Every element with a positive tabindex is visited in ascending order before anything with 0 or a natural position. One tabindex="1" anywhere on a page therefore reorders the whole page, and adding a form field later puts it in a place nobody expects.

What squirrel checks

One rule, three check names, at severity warning. It reads every element carrying a tabindex, matching the attribute name case-insensitively so React’s tabIndex in server-rendered markup counts, and parses the value as an integer. Values of 0 and -1 are skipped, and a non-numeric value such as auto is ignored.

  • tabindex-very-high fails with N element(s) with very high tabindex values for values above 100, carrying the issue Very high tabindex values indicate misuse. Items read div#hero (tabindex=9999), up to ten with a count of the rest.
  • tabindex-positive warns with N element(s) with positive tabindex for values from 1 to 100, suggesting Use natural document order instead. Items read the same way, up to ten with a count of the rest.
  • tabindex passes with Tabindex values are appropriate (0 or -1) when the page uses the attribute and no value is positive.
  • tabindex returns info with No tabindex attributes found.

How to fix it

<div role="button" tabindex="0">Save</div>

Delete the number and reorder the markup instead. Source order is what the tab sequence follows, and CSS can move things visually without touching it. Where visual and source order disagree badly, that is usually a layout problem worth fixing on its own.

Use tabindex="-1" for things focus should reach only from script: a dialog container, the target of a skip link, a region you move focus to after a route change.

Rule IDa11y/tabindex
CategoryAccessibility
ScopePer-page
Severitywarning
Weight5/10

Enable / disable

Disable this rule

[rules]
disable = ["a11y/tabindex"]

Disable all Accessibility rules

[rules]
disable = ["a11y/*"]

Enable only this rule

[rules]
enable = ["a11y/tabindex"]

enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.

Accessibility findings ship in every audit next to the SEO, performance and agent experience rules. See Website security scan with AI for how an agent works through a report.

References

Check your site

Run squirrel audit https://example.com and open the Accessibility section of the report. Values above 100 are reported separately, since they almost always mean the attribute is being misused. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.

Type to search…

↑↓ navigate↵ openesc close