jsx-a11y/no-noninteractive-tabindex
Disallow tabIndex of 0 or more on non-interactive elements
Also called jsx_a11y/no-noninteractive-tabindex
Every element with tabIndex={0} is one more stop for the Tab key, and a keyboard user expects to be able to do something at each stop. A stop on plain content gives them nothing to do and puts the real controls further away.
tabIndex={-1} isn't reported, because it lets your code call focus() on the element without adding a stop. Interactive elements, and elements with an interactive role such as button, can have any tabIndex. Components aren't checked.
Configure#
Off by default. To turn it on:
[lint.rules]
"jsx-a11y/no-noninteractive-tabindex" = "error" # or "warn"Every option, set to its default:
[lint.rules]
"jsx-a11y/no-noninteractive-tabindex" = ["error", {
tags = [], # list of strings
roles = ["tabpanel"],
allowExpressionValues = true,
}]Examples#
const summary = <article tabIndex={0}tabIndex should only be declared on interactive elements.>{post.summary}</article>;
const box = <div tabIndex="0"tabIndex should only be declared on interactive elements. />;const summary = <article>{post.summary}</article>;
const heading = <h1 tabIndex={-1}>{post.title}</h1>;
const toggle = <div role="button" tabIndex={0} onClick={expand} />;Options#
| Option | Default | What it does |
|---|---|---|
tags | [] | Elements that can have a tabIndex. |
roles | ["tabpanel"] | Non-interactive roles that can have a tabIndex. Your list replaces the default. |
allowExpressionValues | true | Allow a tabIndex or a role that is only known at run time, such as a variable. |
{ "tags": ["pre"] }No problemsconst code = <pre tabIndex={0}>{source}</pre>;const panel = <div role="tabpanel" tabIndex={0} />;{ "roles": ["region"] }1 problemconst panel = <div role="tabpanel" tabIndex={0}tabIndex should only be declared on interactive elements. />;With allowExpressionValues: false, a tabIndex that is a variable is reported on every element, even on a <button> or a component:
const row = <div tabIndex={rowTabIndex} />;
const next = <button tabIndex={rowTabIndex} />;
const cell = <Cell tabIndex={rowTabIndex} />;{ "allowExpressionValues": false }3 problemsconst row = <div tabIndex={rowTabIndex}tabIndex should only be declared on interactive elements. />;
const next = <button tabIndex={rowTabIndex}tabIndex should only be declared on interactive elements. />;
const cell = <Cell tabIndex={rowTabIndex}tabIndex should only be declared on interactive elements. />;A conditional doesn't count as unknown. The rule looks at its first branch:
const row = <div tabIndex={isActive ? 0 : -1}tabIndex should only be declared on interactive elements. />;