💼 This rule is enabled in the following configs: ☑️ recommended
, 🔒 strict
.
Non-interactive HTML elements and non-interactive ARIA roles indicate content and containers in the user interface. A non-interactive element does not support event handlers (mouse and key handlers). Non-interactive elements include <main>
, <area>
, <h1>
(,<h2>
, etc), <p>
, <img>
, <li>
, <ul>
and <ol>
. Non-interactive WAI-ARIA roles include article
, banner
, complementary
, img
, listitem
, main
, region
and tooltip
.
Move the event handler function to an inner element that is either a semantically interactive element (<button>
, <a href>
) or that has an interactive role. This leaves the content or container semantic value of this element intact.
Common interactive roles include:
button
link
checkbox
menuitem
menuitemcheckbox
menuitemradio
option
radio
searchbox
switch
textbox
Note: Adding a role to your element does not add behavior. When a semantic HTML element like <button>
is used, then it will also respond to Enter key presses when it has focus. The developer is responsible for providing the expected behavior of an element that the role suggests it would have: focusability and key press support.
see WAI-ARIA Authoring Practices Guide - Design Patterns and Widgets.
Move the event handler function to an inner element like <div>
and give that element a role of presentation
. This leaves the content or container semantic value of this element intact.
<div role="article">
<div
onClick="onClickHandler"
onKeyPress={onKeyPressHandler}
role="presentation">
{this.props.children}
</div>
</div>
Marking an element with the role presentation
indicates to assistive technology that this element should be ignored; it exists to support the web application and is not meant for humans to interact with directly.
Headers often double as expand/collapse controls for the content they headline. An accordion component is a common example of this pattern. Rather than assign the interaction handling code to the heading itself, put a button inside the heading instead. This pattern retains the role of the heading and the role of the button.
<h3>
<button onClick={this._expandSection}>News</button>
</h3>
<ul id="articles-list">
<li>...</li>
</ul>
Table cells (and tables in general) are meant to contain data. ARIA provides us with a construct called a Grid that is essentially a 2 dimensional logical container for content and interactive elements.
You have two options in this case.
For instance, move the button inside the cell:
<table>
<tr>
<td><button>Sort</button></td>
</tr>
</table>
This preserves the table cell semantics and the button semantics; the two are not conflated on the cell.
If your user interface has a table-like layout, but is filled with interactive components in the cells, consider converting the table into a grid.
<table role="grid">
<tr>
<td role="gridcell" onClick={this.sort}>Sort</td>
</tr>
</table>
You can also put the interactive content inside the grid cell. This maintains the semantic distinction between the cell and the interaction content, although a grid cell can be interactive.
You may configure which handler props should be taken into account when applying this rule. The recommended configuration includes the following 6 handlers.
'jsx-a11y/no-noninteractive-element-interactions': [
'error',
{
handlers: [
'onClick',
'onMouseDown',
'onMouseUp',
'onKeyPress',
'onKeyDown',
'onKeyUp',
],
},
],
Adjust the list of handler prop names in the handlers array to increase or decrease the coverage surface of this rule in your codebase.
<div onClick={() => void 0} role="button" />
<div onClick={() => void 0} role="presentation" />
<input type="text" onClick={() => void 0} /> // Interactive element does not require role.
<button onClick={() => void 0} className="foo" /> // button is interactive.
<div onClick={() => void 0} role="button" aria-hidden /> // This is hidden from screenreader.
<Input onClick={() => void 0} type="hidden" /> // This is a higher-level DOM component
<li onClick={() => void 0} />
<div onClick={() => void 0} role="listitem" />