DEV Community

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

Posted on • Edited on

13 2 1

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/space 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.key === "Enter" || e.key === " ") {
    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 filterKeyTriggerButton(handler) {
  return e => {
    if (e.key === "Enter" || e.key === " ") {
      handler(e);
    }
  }
}

export function accessibleOnClick(handler) {
  return {
    role: 'button',
    tabIndex: tabIndex ?? 0,
    onKeyDown: filterKeyTriggerButton(handler),
    onClick: handler
  }
}


Enter fullscreen mode Exit fullscreen mode

TypeScript version:



export function filterKeyTriggerButton(
  handler: (e: React.KeyboardEvent) => void
) {
  return (e: React.KeyboardEvent) => {
    if (e.key === "Enter" || e.key === " ") {
      handler(e);
    }
  };
}

export function accessibleOnClick(
  handler: (e: React.KeyboardEvent | React.MouseEvent) => void,
  tabIndex?: number
) {
  return {
    role: "button",
    tabIndex: tabIndex ?? 0,
    onKeyDown: filterKeyTriggerButton(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!

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay