{"record":{"id":"d6ce13c3ec678e2c","repo":"oxc-project/oxc","slug":"non-interactive-elements-should-not-be-assigned-mo","errorCode":null,"errorMessage":"Non-interactive elements should not be assigned mouse or keyboard event listeners.","messagePattern":"Non-interactive elements should not be assigned mouse or keyboard event listeners\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/jsx_a11y/no_noninteractive_element_interactions.rs","lineNumber":29,"sourceCode":"use oxc_str::CompactStr;\nuse rustc_hash::FxHashMap;\nuse schemars::JsonSchema;\nuse serde::Deserialize;\n\nuse crate::{\n    AstNode,\n    context::LintContext,\n    globals::HTML_TAG,\n    rule::{DefaultRuleConfig, Rule},\n    utils::{\n        get_element_type, get_prop_value, get_string_literal_prop_value, has_jsx_prop,\n        has_jsx_prop_ignore_case, is_hidden_from_screen_reader, is_interactive_element,\n        is_interactive_role, is_non_interactive_element, is_non_interactive_role, parse_jsx_value,\n    },\n};\n\nfn no_noninteractive_element_interactions_diagnostic(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\n        \"Non-interactive elements should not be assigned mouse or keyboard event listeners.\",\n    )\n    .with_help(\n        \"Move the handler to an interactive element, or use an appropriate interactive role.\",\n    )\n    .with_label(span)\n}\n\nconst RECOMMENDED_HANDLERS: &[&str] = &[\n    // image\n    \"onError\",\n    \"onLoad\",\n    // keyboard\n    \"onKeyPress\",\n    \"onKeyDown\",\n    \"onKeyUp\",\n    // focus\n    \"onFocus\",","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/jsx_a11y/no_noninteractive_element_interactions.rs#L11-L47","documentation":"This is the `jsx_a11y/no-noninteractive-element-interactions` rule in oxlint. It fires when a non-interactive HTML element (per `is_non_interactive_element`, e.g. `<li>`, `<td>`, `<h1>`) is assigned a mouse or keyboard event handler such as `onClick` or `onKeyDown`. Screen-reader users get no affordance that the element is operable, so handlers belong on interactive elements.","triggerScenarios":"A non-interactive HTML element carries a handler prop (via `get_prop_value`) that is not in the allowed `RECOMMENDED_HANDLERS` list (which permits things like `onError`/`onLoad` on images), the element is not hidden from screen readers, has no interactive role, and the pairing is not exempted by the rule's `handlers`/role config.","commonSituations":"`<li onClick>` in hand-rolled menus and listboxes; `<td onClick>` in clickable table rows; `<h2 onClick>` acting as a disclosure toggle; components built before the team adopted jsx-a11y.","solutions":["Move the handler to a real interactive element such as `<button>` inside the non-interactive one.","Give the element an interactive role plus `tabIndex` and keyboard handlers (e.g. `role=\"button\" tabIndex={0} onKeyDown={...}`).","Add the specific handler name to the rule's `handlers` config if it is intentionally non-pointer (like `onMouseOver`)."],"exampleFix":"// before\n<li onClick={() => select(item)}>{item.name}</li>\n\n// after\n<li><button onClick={() => select(item)}>{item.name}</button></li>","handlingStrategy":"validation","validationCode":"npx oxlint --jsx-a11y/no-noninteractive-element-interactions src/","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Default to <button> for anything clickable inside lists/tables/headings.","Keep intentional exceptions (onError/onLoad on media) in the rule's handler config.","Add keyboard equivalents whenever you move a handler onto an element."],"tags":["jsx-a11y","react","accessibility","event-handlers","lint"],"backgroundTag":"noninteractive-element-event-handlers","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}