Skip to content

feat(linter): implement jsx-a11y/no-noninteractive-element-interactions#17608

Closed
Kenzo-Wada wants to merge 9 commits into
oxc-project:mainfrom
Kenzo-Wada:feat/jsx-a11y-no-noninteractive-element-interactions
Closed

feat(linter): implement jsx-a11y/no-noninteractive-element-interactions#17608
Kenzo-Wada wants to merge 9 commits into
oxc-project:mainfrom
Kenzo-Wada:feat/jsx-a11y-no-noninteractive-element-interactions

Conversation

@Kenzo-Wada

@Kenzo-Wada Kenzo-Wada commented Jan 3, 2026

Copy link
Copy Markdown
Contributor

related: #1141

This PR is published with my friend Claude Code Max(model: opus 4.5). but all reviewed by me, and i am responsible for all the changes.

@Kenzo-Wada Kenzo-Wada requested a review from camc314 as a code owner January 3, 2026 17:08
Copilot AI review requested due to automatic review settings January 3, 2026 17:08
@github-actions github-actions Bot added A-linter Area - Linter C-enhancement Category - New feature or request labels Jan 3, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements the jsx-a11y/no-noninteractive-element-interactions linter rule to enforce accessibility best practices by preventing mouse and keyboard event handlers on non-interactive HTML elements and ARIA roles.

Key changes:

  • Adds rule logic to detect event handlers on semantic non-interactive elements (like <li>, <h1>, <article>) and elements with non-interactive ARIA roles
  • Distinguishes between interactive and non-interactive roles, with special handling for abstract roles
  • Integrates with existing accessibility utilities for screen reader visibility and presentation role detection

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
crates/oxc_linter/src/rules/jsx_a11y/no_noninteractive_element_interactions.rs Main rule implementation with element/role classification, handler detection logic, and comprehensive test cases
crates/oxc_linter/src/rules.rs Registers the new rule module in the jsx_a11y rules collection
crates/oxc_linter/src/generated/rule_runner_impls.rs Adds RuleRunner implementation specifying JSXOpeningElement as the target node type
crates/oxc_linter/src/snapshots/jsx_a11y_no_noninteractive_element_interactions.snap Test snapshot file capturing expected diagnostic output for all test cases

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/oxc_linter/src/rules/jsx_a11y/no_noninteractive_element_interactions.rs Outdated
@codspeed-hq

codspeed-hq Bot commented Jan 3, 2026

Copy link
Copy Markdown

CodSpeed Performance Report

Merging this PR will not alter performance

Comparing Kenzo-Wada:feat/jsx-a11y-no-noninteractive-element-interactions (980b533) with main (fd2c792)

Summary

✅ 4 untouched benchmarks
⏩ 41 skipped benchmarks1

Footnotes

  1. 41 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

…_interactions.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Kenzo Wada <79452224+Kenzo-Wada@users.noreply.github.com>
@connorshea

Copy link
Copy Markdown
Member

Updated the PR description with the original docs/source/tests for ease of review :)

@camc314 camc314 self-assigned this Jan 5, 2026
@connorshea

Copy link
Copy Markdown
Member

I've implemented is_abstract_role in this PR: #17817, you should update this rule to use it once that PR lands.

@connorshea

Copy link
Copy Markdown
Member

I have now also added is_non_interactive_element and is_interactive_role in that PR. This PR should be updated to use those methods as well to ensure accuracy/consistency once merged.

There are a large number of tests missing in this implementation as well, for example all tests for the recommended options (the recommended config match the defaults in this impl and so should be added/pass), like the one for onCompositionUpdate: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/8f75961d965e47afb88854d324bd32fafde7acfe/__tests__/src/rules/no-noninteractive-element-interactions-test.js#L396

More tests are missing, such as the ones listed in the neverValid array (<dfn onClick={() => {}} />, etc.). The tests must all be ported correctly and made to pass. Unfortunately our rulegen tool does not handle the jsx-a11y rules well, and so this must be done manually.

There is also missing logic, such as an equivalent to the isContentEditable check from the original rule. The tests related to this were ported and do pass, but I assume this is due to a separate logical issue in the code somewhere, and fixing other tests will result in the contenteditable tests failing.

I am assuming this was PR generated using AI tooling, accordingly please update the PR description to note any and all AI usage in accordance with our policy, preferably including models/tools used and a confirmation that you have personally reviewed the code generated and ensured it works/makes sense: https://oxc.rs/docs/contribute/introduction.html#ai-usage-policy

If the PR description is not updated in a timely manner, we will opt to close this PR to avoid maintainer fatigue and prevent spending too much time on contributions not thoroughly reviewed by the contributor.

@Kenzo-Wada

Copy link
Copy Markdown
Contributor Author

ill fix it on few days! thanks for your review :)

Kenzo-Wada and others added 5 commits January 16, 2026 15:55
…_interactions.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Kenzo Wada <79452224+Kenzo-Wada@users.noreply.github.com>
@coreyward

Copy link
Copy Markdown

Any word on what's left for this?

@camchenry camchenry self-assigned this Apr 23, 2026
Comment on lines +103 to +262
const NON_INTERACTIVE_ROLES: &[&str] = &[
"alert",
"alertdialog",
"application",
"article",
"banner",
"blockquote",
"caption",
"cell",
"code",
"complementary",
"contentinfo",
"definition",
"deletion",
"dialog",
"directory",
"document",
"emphasis",
"feed",
"figure",
"form",
"generic",
"group",
"heading",
"img",
"insertion",
"list",
"listitem",
"log",
"main",
"marquee",
"math",
"meter",
"navigation",
"note",
"paragraph",
"region",
"rowgroup",
"search",
"separator",
"status",
"strong",
"subscript",
"superscript",
"table",
"tabpanel",
"term",
"time",
"timer",
"tooltip",
];

const INTERACTIVE_ROLES: &[&str] = &[
"button",
"checkbox",
"columnheader",
"combobox",
"grid",
"gridcell",
"link",
"listbox",
"menu",
"menubar",
"menuitem",
"menuitemcheckbox",
"menuitemradio",
"option",
"progressbar",
"radio",
"radiogroup",
"row",
"rowheader",
"scrollbar",
"searchbox",
"slider",
"spinbutton",
"switch",
"tab",
"tablist",
"textbox",
"toolbar",
"tree",
"treegrid",
"treeitem",
];

const ABSTRACT_ROLES: &[&str] = &[
"command",
"composite",
"input",
"landmark",
"range",
"roletype",
"section",
"sectionhead",
"select",
"structure",
"widget",
"window",
];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use some helpers introduced by #17817 such as is_non_interactive_element instead of hard coding

@camc314

camc314 commented May 12, 2026

Copy link
Copy Markdown
Contributor

close as stale

@camc314 camc314 closed this May 12, 2026
camchenry pushed a commit that referenced this pull request May 12, 2026
…2337)

## Summary

Adds the `jsx-a11y/no-noninteractive-element-interactions` rule to
oxlint.

This rule reports mouse/keyboard event handlers on non-interactive
elements or elements with non-interactive ARIA roles, while respecting
interactive elements, interactive/abstract/presentation roles, hidden
content, `contentEditable`, custom component mappings, and handler
exception configuration.

## Notes

- Test coverage is based on the upstream `eslint-plugin-jsx-a11y` rule
fixtures.
- There is an earlier open PR for this same rule at
#17608; this PR is a fresh
implementation/review pass for that rule.
- This follows the structure and conventions from the related
`jsx-a11y/no-noninteractive-element-to-interactive-role` work in
#21264.
- The local test suite intentionally keeps `separator` and `progressbar`
behavior tied to Oxc's existing shared ARIA role utilities for now.
- Upstream expects `role="separator"` to report and `role="progressbar"`
to pass. Oxc's current shared role classification leads to the opposite
behavior for those two cases, so I would like maintainer guidance on
whether this rule should add rule-specific overrides or whether the
shared utilities should change.

## Testing

- `cargo +stable fmt --check`
- `cargo +stable test -p oxc_linter --
no_noninteractive_element_interactions`
- `cargo +stable insta pending-snapshots`
- `git diff --check`

## Disclosure

I used Pi and Codex with GPT-5.5 to help prepare these changes, and
manually reviewed everything before opening this PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-linter Area - Linter C-enhancement Category - New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants