Disallow non-interactive HTML elements from being assigned interactive ARIA roles.
Assigning an interactive role (button, checkbox, menuitem, ...) to an element with inherent non-interactive semantics (headings, landmarks, text structure, lists, tables, forms) creates a widget with no supporting behavior — focus, keyboard activation, and state handling must all be added manually, and the mismatch is easy to get wrong.
The set of non-interactive elements is sourced from axobject-query — the same AX-tree-derived data used by eslint-plugin-jsx-a11y, @angular-eslint/eslint-plugin-template, and others. It includes headings (<h1>–<h6>), landmarks (<article>, <aside>, <nav>, <main>, etc.), text structure (<p>, <figure>, <blockquote>, etc.), lists (<ul>, <ol>, <li>, <dl>, <dt>, <dd>), tables (<table>, <tbody>, <tr>, etc.), forms (<form>, <fieldset>, <legend>), <img>, and similar.
<div> and <span> are not covered — ARIA 1.2 assigns them the generic role with no inherent semantics to mismatch. <div role="button"> is covered by the related template-require-aria-activedescendant-tabindex and template-no-noninteractive-tabindex rules.
This rule forbids the following:
<template>
<h1 role="button">Click</h1>
<article role="button">Story</article>
<li role="tab">Tab</li>
<img role="link" src="/x.png" alt="link" />
<form role="checkbox"></form>
<p role="button">Click me</p>
</template>This rule allows the following:
<template>
<h1 role="heading" aria-level="1">Title</h1>
<article role="article">Story</article>
<ul role="list"></ul>
{{! <div>/<span> are "generic" — not covered by this rule }}
<div role="button" tabindex="0"></div>
<span role="checkbox" aria-checked="false" tabindex="0"></span>
</template>- WAI-ARIA 1.2 — Role taxonomy
- HTML-AAM — Element role mappings
axobject-query— the shared data package used by every major a11y ESLint pluginno-noninteractive-element-to-interactive-role— eslint-plugin-jsx-a11y