The ESLint jsx-a11y plugin helps developers create accessible websites for all users. The plugin has 36 rules (as of publishing this post) for writing WCAG and WAI-ARIA compliant code.
In this post I will give three examples of breaking the interactive-supports-focus
rule and the solution. Each example will have:
- Offending code that broke the
interactive-supports-focus
rule - Screenshots of the error output
- Code for fixing the problem
How the “interactive-supports-focus” Rule Gets Broken
The jsx-a11y/interactive-supports-focus rule requires that “Elements with an interactive role and interaction handlers (mouse or key press) must be focusable”, according to the documentation.
Here’s what this means in examples:
- if you have a
div
with an onClick handler, it needs to be focusable - if you have a
span
with role=”button”, it needs to be focusable - Any non-form element that has an interaction handler or a form element role (i.e. button, menu, checkbox) it needs to be focusable
The easiest way to make the element focusable is to add tabIndex="0"
.
The Difference Between Tabbable and Focusable
I will paraphrase allyjs.io: Focusable means the element can be programmatically focused, and maybe focused via mouse events, but not by tabbing. Tabbable includes focusable plus the element can be tabbed too. This means ‘focusable’ is a subset of ‘tabbable’.
There is also a ‘tabbable only’ scenario which means the element can only gain focus via the keyboard tab button.
Rule Options
The jsx-a11y/interactive-supports-focus
rule can be configured with an option that requires elements to be tabbable (which implies they can be focused via tab key, mouse events, and programmatically).
Here is an example configuration:
{
'jsx-a11y/interactive-supports-focus': [
'error',
{
tabbable: [
'button',
'checkbox',
'link',
'textbox',
'tree'
],
},
]
}
jsx-a11y/interactive-supports-focus Examples
I set the rule to “error” instead of “warn” for the following scenarios. This is makes the compiler fail when a jsx-a11y rule is broken.
How to Fix “Interactive Role Must Be Tabbable” (Button Example)
I created a div with an onClick
and onKeyPress
event handler and a role of “button
“. This triggers the interactive-supports-focus rule if no tabIndex
is specified.
<div onClick={eventHandler} onKeyPress={eventHandler} role="button">Div Button</div>
![Elements with the 'button' interactive role must be tabbable jsx-a11y/interactive-supports-focus](https://i0.wp.com/smartdevpreneur.com/wp-content/uploads/2022/06/image-43.png?resize=814%2C289&ssl=1)
In order to be tabbable, the tabIndex
needs to be greater than or equal to 0.
<div onClick={eventHandler} onKeyPress={eventHandler} role="button" tabIndex={0}>Div Button</div>
Interestingly, when I set tabIndex={-1}
this satisfied the rule. However, this makes the HTML element focusable programmatically but not tabbable with the keypad.
Another (better) solution is to use a button
element instead of a div
. The button
will convey more semantic information.
How to Fix “Interactive Role Must Be Focusable” (Button Example)
Again I created a div with an onClick
and onKeyPress
event handler and a role of “button
“. This triggers the interactive-supports-focus rule if no tabIndex
is specified.
<div onClick={eventHandler} onKeyPress={eventHandler} role="button">Focus Div</div>
However, this time I set no options in the interactive-supports-focus
rule. This means the div with role="button"
is only required to be focusable.
![Elements with the 'button' interactive role must be focusable jsx-a11y/interactive-supports-focus](https://i0.wp.com/smartdevpreneur.com/wp-content/uploads/2022/06/image-44.png?resize=801%2C287&ssl=1)
In order to be focusable, the tabIndex
must be greater than or equal to -1.
<div onClick={eventHandler} onKeyPress={eventHandler} role="button" tabIndex={-1}>Div Button</div>
This can be considered less strict than requiring the element to to be accesible via tabbing.
How to Fix “Elements with ‘link’ Interactive Role Must Be Tabbable”
I created a span with onClick
and onKeyPress
events and role=”link”, but no tabIndex
.
<span onClick={navToGoogle} onKeyPress={navToGoogle} role="link">Nav to Google</span>
I required the link to be tabbable, not just focusable:
![Elements with the 'link' interactive role must be tabbable jsx-a11y/interactive-supports-focus](https://i0.wp.com/smartdevpreneur.com/wp-content/uploads/2022/06/image-45.png?resize=780%2C309&ssl=1)
In this case, instead of adding tabIndex
, I stopped using a span
and switched to an anchor tag instead:
<a href="google.com">Nav to Google</a>
This is the best solution in most situations. A span
usually shouldn’t be used to do the job of an a
tag. The anchor tag is going to give search engines and users more information about the intent of the element.
How to Disable the jsx-a11y/interactive-supports-focus Rule
If you want to disable the rule completely, set the first value in the options array to 0
(“none”) is not a valid value.
"jsx-a11y/interactive-supports-focus": [
0,
{
"tabbable": [
"button",
"link"
]
}
]
If you want to simply get warnings, set the value to 1
or “warn” (both are valid). This will print the same text as “error” but will not block the compiler from completing successfully if a rule is broken.
Related Posts
Check out these posts on ESLint and jsx-a11y: