oxc-project/oxc · warning
Static HTML elements with event handlers require a role.
Error message
Static HTML elements with event handlers require a role.
What it means
This is the `jsx_a11y/no-static-element-interactions` rule in oxlint. It fires when a static (non-interactive, non-interactive-role, non-hidden) HTML element carries one of the default interaction handlers — `onClick`, `onMouseDown`, `onMouseUp`, `onKeyPress`, `onKeyDown`, `onKeyUp` (see `DEFAULT_HANDLERS`) or a configured `handlers` entry — without any ARIA role. A clickable `<div>` with no role is invisible as an operable control to assistive tech.
Source
Thrown at crates/oxc_linter/src/rules/jsx_a11y/no_static_element_interactions.rs:27
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::{GetSpan, Span};
use oxc_str::CompactStr;
use crate::{
AstNode,
context::LintContext,
globals::HTML_TAG,
rule::{DefaultRuleConfig, Rule},
utils::{
get_element_type, get_prop_value, has_jsx_prop, has_jsx_prop_ignore_case, is_abstract_role,
is_hidden_from_screen_reader, is_interactive_element, is_interactive_role,
is_non_interactive_element, is_non_interactive_role, is_presentation_role,
},
};
fn no_static_element_interactions_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn("Static HTML elements with event handlers require a role.")
.with_help("Add a role attribute to this element, or use a semantic HTML element instead.")
.with_label(span)
}
const DEFAULT_HANDLERS: &[&str] =
&["onClick", "onMouseDown", "onMouseUp", "onKeyPress", "onKeyDown", "onKeyUp"];
#[derive(Debug, Default, Clone, Deserialize)]
pub struct NoStaticElementInteractions(Box<NoStaticElementInteractionsConfig>);
impl std::ops::Deref for NoStaticElementInteractions {
type Target = NoStaticElementInteractionsConfig;
fn deref(&self) -> &Self::Target {
&self.0
}
}
View on GitHub (pinned to e1e7af627c)
Solutions
- Replace the static element with `<button>` (styled to reset defaults) so semantics come free.
- Add an appropriate `role` (e.g. `role="button"`) plus `tabIndex={0}` and keyboard handlers when a real button is impossible.
- Extend the rule's `handlers` config for legitimate non-pointer cases like `onMouseDown` on drag containers.
- Disable inline only for genuinely mouse-only affordances (rare; prefer `role="presentation"` + documented reason).
Example fix
// before
<div onClick={() => setOpen(true)}>Show details</div>
// after
<button type="button" onClick={() => setOpen(true)}>Show details</button> Defensive patterns
Strategy: validation
Validate before calling
npx oxlint --jsx-a11y/no-static-element-interactions src/
Prevention
- Use <button> for click targets; style resets are cheaper than ARIA repairs.
- If you must keep a div, pair role + tabIndex + onKeyDown together.
- Extend the handlers config for legit non-pointer cases instead of disabling the rule.
When it happens
Trigger: A JSX element whose type is a static HTML tag (per `HTML_TAG` + `is_non_interactive_element`), carrying a handler from the checked list, while `get_prop_value` finds no `role` attribute, the role is not presentation/abstract, and the element is not hidden from screen readers.
Common situations: Clickable div cards, drag-and-drop surfaces, dismiss-on-click overlays, custom cells in data grids; the single most common violation when a team first enables jsx-a11y recommended.
Related errors
- Interactive elements should not be assigned non-interactive
- Non-interactive elements should not be assigned mouse or key
- Non-interactive elements should not be assigned interactive
- The `{element}` element has an implicit role of `{role}`. De
- Prefer `{tag}` over `role` attribute `{role}`.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/c9e59c9c8406e6e2.
Report an issue: GitHub.