jsx-a11y/no-interactive-element-to-noninteractive-role

Disallow non-interactive ARIA roles on interactive elements

Also called jsx_a11y/no-interactive-element-to-noninteractive-role

A role replaces what a screen reader says about an element. A <button role="heading"> is announced as a heading, so the user never finds out they can press it, even though it still takes focus and reacts to clicks.

Interactive elements include <button>, <input>, <select>, <textarea> and <a> with an href. Non-interactive roles include article, heading, img, list and listitem, and also presentation and none. Only a role written as a string is checked.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"jsx-a11y/no-interactive-element-to-noninteractive-role" = "error" # or "warn"

Examples#

example.jsx2 problems
const title = <button role="heading" onClick={toggle}>Details</button>;
const item = <a href="/settings" role="listitem">Settings</a>;
example.jsxNo problems
const title = (
  <h2>
    <button onClick={toggle}>Details</button>
  </h2>
);

const item = (
  <li>
    <a href="/settings">Settings</a>
  </li>
);

An interactive role on an interactive element is fine:

example.jsxNo problems
const tab = <button role="tab">Profile</button>;

Options#

The option is an object that maps an element to the roles it's allowed to have. The default is:

{
  "tr": ["none", "presentation"],
  "canvas": ["img"]
}

Your object replaces the default, so repeat the entries you want to keep.

example.jsxNo problems
const chart = <canvas role="img" aria-label="Sales by month" />;
example.jsxwith { "input": ["img"] }1 problem
const chart = <canvas role="img" aria-label="Sales by month" />;
example.jsxwith { "input": ["img"] }No problems
const logo = <input type="image" role="img" alt="Logo" />;