Skip to content
Latchkey

eslint-plugin-jsx-a11y "onClick must be accompanied by onKeyDown" in CI

The jsx-a11y/click-events-have-key-events rule flags a non-interactive element (like a <div>) with an onClick but no keyboard handler. Keyboard users cannot trigger it, violating WCAG 2.1.1.

What this error means

ESLint reports "Visible, non-interactive elements with click handlers must have at least one keyboard listener (jsx-a11y/click-events-have-key-events)" on a <div onClick=...> and fails the lint step.

eslint
/src/components/Card.jsx
  8:5  error  Visible, non-interactive elements with click handlers must have at
             least one keyboard listener  jsx-a11y/click-events-have-key-events

Common causes

A div or span is used as a button

A non-interactive element carries an onClick with no keyboard equivalent, so keyboard and screen reader users cannot activate it.

No role or keyboard handler was added

The element lacks an interactive role, tabindex, and an onKeyDown/onKeyUp, so it is unreachable and unusable by keyboard.

How to fix it

Use a real button element

The cleanest fix is a native <button>, which is focusable and keyboard-activatable by default and satisfies the rule.

Card.jsx
<button type="button" onClick={onClick}>Open</button>

Add role, tabindex, and a key handler

  1. If it must stay a div, add role="button" and tabIndex={0}.
  2. Add an onKeyDown that activates on Enter and Space.
  3. Re-run ESLint to confirm the rule passes.
Card.jsx
<div role="button" tabIndex={0} onClick={onClick}
     onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') onClick(e); }}>
  Open
</div>

How to prevent it

  • Prefer native interactive elements over click-handling divs.
  • When a div must be interactive, add role, tabindex, and key handlers.
  • Keep the rule at error so keyboard gaps fail lint.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →