DEV Community

Cover image for Easy Accessible Click Handlers
Andreas Riedmüller
Andreas Riedmüller

Posted on

Easy Accessible Click Handlers

If you add a click event to a non-interactive html element such as a div you should also add keyboard support. For interactive elements like a button this is already taken care of by the browser.

If you use eslint-plugin-jsx-a11y you will see this warning when you add an onClick event:

71:13  warning  Visible, non-interactive elements with click handlers must have at least one keyboard listener jsx-a11y/click-events-have-key-events
Enter fullscreen mode Exit fullscreen mode

To get rid of this warning, my default approach is to add an additional handler for onKeyDown, filter for the enter key and trigger the same event as I have for onClick.

Additionally I add the role and tabIndex attributes as recommended.

function handleClick() { setWhatever(true) }

function handleKeyDown(e) {
  if (e.keyCode === 13) {
    handleClick();
  }
}

return <div
  role={'button'}
  tabIndex={0}
  onClick={handleClick}
  onKeyDown={handleKeyDown}
>Click me!</div>
Enter fullscreen mode Exit fullscreen mode

In comparison to a button this adds quite a lot of code and makes simple components appear more complex than they really are:

function handleClick() { setWhatever(true) }

return <button onClick={handleClick}>Click me!</button>
Enter fullscreen mode Exit fullscreen mode

To avoid this, you can add a simple helper function that returns all required attributes, I called mine accessibleOnClick:

export function filterKeyEnter(handler) {
  return e => {
    if (e.keyCode === 13) {
      handler(e);
    }
  }
}

export function accessibleOnClick(handler) {
  return {
    role: 'button',
    tabIndex: tabIndex || 0,
    onKeyDown: filterKeyEnter(handler),
    onClick: handler
  }
}
Enter fullscreen mode Exit fullscreen mode

In your JSX you can now use the spread opperator to add all attributes returned by accessibleOnClick.

function handleClick() { setWhatever(true) }

return <div
{...accessibleOnClick(handleClick)}
>Click me!</div>
Enter fullscreen mode Exit fullscreen mode

This is one of my favorite helper functions and I use it on a regular basis.

Do you have a similar/different approach for this type of click handlers? Let me know!

Top comments (0)