react-doctor/no-interactive-element-to-noninteractive-role
Don't override an interactive element's semantics with a non-interactive role.
- Category: Accessibility
- Severity: warn
- Source:
oxlint-plugin-react-doctor - Framework: global
- Enabled when: always
- Documentation: https://oxc.rs/docs/guide/usage/linter/rules/jsx_a11y/no-interactive-element-to-noninteractive-role
Validation prompt
Use this to decide whether a fired diagnostic is real or a false positive.
Fires when a natively interactive HTML element carries a string-literal role= whose first token is a non-interactive role or a presentation role (presentation/none): input (every type, even hidden), button, select, textarea, option, menuitem, datalist, audio, video, canvas, embed, summary, td, th, tr, plus a/area with href and img with usemap. Per-tag allowances are skipped (tr permits none/presentation, canvas permits img). False positive: the role value must be a static string literal — dynamic role={expr}, a forwarded {...props}, or a namespaced ns:role is never inspected, so a finding on those is impossible; also note getElementType remaps custom components via jsx-a11y components settings, so a flagged <Link role="img" /> only fires when Link is mapped to an interactive tag.
Fix prompt
Use this once validation confirms the diagnostic is real.
Don't paper over an interactive control with a static role — either drop the conflicting role so the native semantics stand (<button>Save</button> instead of <button role="img">), or if the element is genuinely meant to be non-interactive, swap it for the right non-interactive element (use <div role="img" aria-label="..."> rather than <a href role="img">). Keep interactive roles (button, link, checkbox, etc.) on interactive elements, and reserve role="presentation"/"none" for purely decorative non-interactive tags. See https://oxc.rs/docs/guide/usage/linter/rules/jsx_a11y/no-interactive-element-to-noninteractive-role
Related rules
More Accessibility rules from the rules reference:
react-doctor/no-justified-text: Use `text-align: left` for body text, or add `hyphens: auto` and `overflow-wrap: break-word` if you must justifyreact-doctor/no-noninteractive-element-interactions: Move the interaction to a semantic interactive element, or add an interactive role plus keyboard support.react-doctor/no-noninteractive-element-to-interactive-role: Use a semantic interactive element instead of role-promoting a non-interactive one.react-doctor/no-noninteractive-tabindex: Reserve tabIndex for interactive elements or interactive roles; remove it from non-interactive ones.react-doctor/no-outline-none: Use `:focus-visible { outline: 2px solid var(--color-muted); outline-offset: 2px }` to show focus only for keyboard users while hiding it for mouse clicks