{"record":{"id":"084d92d1a471076c","repo":"oxc-project/oxc","slug":"aria-hidden-must-not-be-true-on-focusable-elemen","errorCode":null,"errorMessage":"`aria-hidden` must not be true on focusable elements.","messagePattern":"`aria-hidden` must not be true on focusable elements\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/jsx_a11y/no_aria_hidden_on_focusable.rs","lineNumber":17,"sourceCode":"use oxc_ast::{\n    AstKind,\n    ast::{JSXAttributeItem, JSXAttributeValue, JSXOpeningElement},\n};\nuse oxc_diagnostics::OxcDiagnostic;\nuse oxc_macros::declare_oxc_lint;\nuse oxc_span::Span;\n\nuse crate::{\n    AstNode,\n    context::LintContext,\n    rule::Rule,\n    utils::{get_element_type, has_jsx_prop_ignore_case, parse_jsx_value},\n};\n\nfn no_aria_hidden_on_focusable_diagnostic(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"`aria-hidden` must not be true on focusable elements.\")\n        .with_help(\"Remove `aria-hidden=\\\"true\\\"` from focusable elements or modify the element to be not focusable.\")\n        .with_label(span)\n}\n\n#[derive(Debug, Default, Clone)]\npub struct NoAriaHiddenOnFocusable;\n\ndeclare_oxc_lint!(\n    /// ### What it does\n    ///\n    /// Enforces that `aria-hidden=\"true\"` is not set on focusable elements.\n    ///\n    /// ### Why is this bad?\n    ///\n    /// `aria-hidden=\"true\"` on focusable elements can lead to confusion or unexpected behavior for screen reader users.\n    ///\n    /// ### Examples\n    ///","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/jsx_a11y/no_aria_hidden_on_focusable.rs#L1-L35","documentation":"This is the `jsx_a11y/no-aria-hidden-on-focusable` rule in oxlint. It fires when an element has `aria-hidden=\"true\"` (parsed via `parse_jsx_value`) but is still focusable — for example it has a non-negative `tabIndex` or is natively interactive. The element disappears from assistive tech while remaining in the tab order, so focus lands on an invisible element.","triggerScenarios":"A JSX element with `aria-hidden` resolving to `true` combined with focusability: `tabIndex={0}` (or any non-negative value), or an inherently interactive element such as `<a href>`, `<button>`, `<input>` that also sets `aria-hidden=\"true\"`.","commonSituations":"Hiding decorative icons that were wrapped in a focusable container; toggling `aria-hidden` on modal overlays while forgetting to also set `tabIndex=-1` or inert; icon buttons marked hidden but still rendered; conditional UI hidden from screen readers but left clickable.","solutions":["Remove `aria-hidden=\"true\"` from the focusable element.","If the element must stay hidden from AT, make it unfocusable: remove `tabIndex` / set `tabIndex={-1}`, remove `href`, or use the `inert` attribute.","Move `aria-hidden` to a purely decorative inner span instead of the interactive wrapper."],"exampleFix":"// before\n<button aria-hidden=\"true\" tabIndex={0} onClick={doThing} />\n\n// after\n<button onClick={doThing}><span aria-hidden=\"true\">icon</span></button>","handlingStrategy":"validation","validationCode":"npx oxlint --jsx-a11y/no-aria-hidden-on-focusable src/","typeGuard":"const isHiddenButFocusable = (props: Record<string, unknown>) =>\n  props['aria-hidden'] === true &&\n  (Number(props.tabIndex ?? NaN) >= 0 || 'href' in props || props.type === 'button');","tryCatchPattern":null,"preventionTips":["When hiding an element from AT, also remove it from the tab order (tabIndex={-1} or inert).","Never put aria-hidden on interactive controls; hide decorative children instead.","Test tab order with the keyboard after any aria-hidden change."],"tags":["jsx-a11y","react","accessibility","aria","screen-reader","lint"],"backgroundTag":"aria-hidden-focusable","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"}