How to Fix (or Disable) “jsx-a11y/interactive-supports-focus” Errors

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
Elements with the ‘button’ interactive role must be tabbable jsx-a11y/interactive-supports-focus

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
Elements with the ‘button’ interactive role must be focusable jsx-a11y/interactive-supports-focus

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
Elements with the ‘link’ interactive role must be tabbable jsx-a11y/interactive-supports-focus

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:

Share this post:

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.