oxc-project/oxc · warning
Non-interactive elements should not be assigned interactive
Error message
Non-interactive elements should not be assigned interactive roles.
What it means
This is the `jsx_a11y/no-noninteractive-element-to-interactive-role` rule in oxlint. It fires when a non-interactive HTML element (per `is_non_interactive_element`) is given an interactive ARIA role (per `is_interactive_role`), e.g. `<ol role="listbox">` or `<table role="grid">`. The mismatch breaks native semantics and expected keyboard behavior that the interactive role promises.
Source
Thrown at crates/oxc_linter/src/rules/jsx_a11y/no_noninteractive_element_to_interactive_role.rs:24
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use oxc_str::CompactStr;
use rustc_hash::FxHashMap;
use schemars::JsonSchema;
use serde::Deserialize;
use crate::{
AstNode,
context::LintContext,
globals::HTML_TAG,
rule::{DefaultRuleConfig, Rule},
utils::{
get_element_type, has_jsx_prop_ignore_case, is_interactive_role, is_non_interactive_element,
},
};
fn no_noninteractive_element_to_interactive_role_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Non-interactive elements should not be assigned interactive roles.")
.with_help("Remove the interactive role or use an appropriate interactive element instead.")
.with_label(span)
}
/// Default allowed overrides matching the `eslint-plugin-jsx-a11y` recommended config.
fn default_allowed_roles() -> FxHashMap<CompactStr, Vec<CompactStr>> {
let mut map = FxHashMap::default();
map.insert(
CompactStr::new("ul"),
vec![
CompactStr::new("menu"),
CompactStr::new("menubar"),
CompactStr::new("radiogroup"),
CompactStr::new("tablist"),
CompactStr::new("tree"),
CompactStr::new("treegrid"),
],
);View on GitHub (pinned to e1e7af627c)
Solutions
- Use the semantically correct native element (`<select>`, `<button>`, real menu markup) instead of a role override.
- If the role override is a sanctioned pattern (like `ul` -> `menu`), confirm it is in the allowed mapping or add it to the rule's config.
- Restructure so the interactive role lands on an element that also provides full keyboard support.
Example fix
// before
<ol role="listbox" value={v} onChange={c}>...</ol>
// after
<select value={v} onChange={c}>...</select> Defensive patterns
Strategy: validation
Validate before calling
npx oxlint --jsx-a11y/no-noninteractive-element-to-interactive-role src/
Prevention
- Prefer native interactive elements over role overrides on containers.
- If a role override is standard (ul->menu), record it in the allowed-roles config once.
- Run oxlint in CI with the nextjs/jsx-a11y presets before role-heavy refactors.
When it happens
Trigger: A non-interactive element carries a `role` whose literal value resolves to an interactive role, and the (element, role) pair is not whitelisted. Defaults (mirroring eslint-plugin-jsx-a11y, see `default_allowed_roles`) allow e.g. `ul` -> `menu`/`menubar` and a few others, which the user config can override or extend.
Common situations: Building listboxes/menus out of `<ol>`/`<ul>`; converting tables to grids with `role="grid"`; refactors where an element was swapped but the role kept; adopting jsx-a11y recommended config and finding many legacy role overrides.
Related errors
- Interactive elements should not be assigned non-interactive
- The `{element}` element has an implicit role of `{role}`. De
- Static HTML elements with event handlers require a role.
- Prefer `{tag}` over `role` attribute `{role}`.
- The attribute `{attr_name}` is not supported by the role `{r
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/956a6334b9b28ddb.
Report an issue: GitHub.