Skip to content

linter: jsx-a11y/no-redundant-roles incorrect implicit roles for <input> and <header> cause false positives #22743

Description

@duniul

What version of Oxlint are you using?

1.67.0

What command did you run?

oxlint ./App.jsx

What does your .oxlintrc.json (or oxlint.config.ts) config file look like?

{
  "plugins": ["jsx-a11y"],
  "rules": {
    "jsx-a11y/no-redundant-roles": "error"
  }
}

What happened?

jsx-a11y/no-redundant-roles reports two false positives where the role is not actually redundant. eslint-plugin-jsx-a11y does not.

  1. <input role="combobox"> (no list attribute): flagged as having implicit role combobox.
  2. <header role="banner">: flagged as having implicit role banner.

With --fix these role attributes are automatically removed, breaking queries in integration tests due to changed roles.

Minimal reproduction

Create a folder with these three files and run:

npx oxlint@1.67.0 ./App.jsx
See files

package.json

{
  "name": "repro",
  "private": true,
  "scripts": { "lint": "oxlint ./App.jsx" },
  "devDependencies": { "oxlint": "1.67.0" }
}

.oxlintrc.json

{
  "plugins": ["jsx-a11y"],
  "rules": { "jsx-a11y/no-redundant-roles": "error" },
}

App.jsx

export function InputCombobox() {
  return (
    <input
      role='combobox'
      aria-label='Search'
      aria-expanded={false}
      aria-controls='listbox-id'
      aria-autocomplete='list'
      aria-haspopup='listbox'
    />
  )
}

export function HeaderBanner() {
  return (
    <header role='banner' aria-label='Editor topbar'>
      Topbar
    </header>
  )
}
See output
❯ npx oxlint@1.67.0 ./App.jsx

  × jsx-a11y(no-redundant-roles): The `input` element has an implicit role of `combobox`. Defining this explicitly is redundant and should be avoided.
   ╭─[App.jsx:4:7]
 3 │     <input
 4 │       role='combobox'
   ·       ───────────────
 5 │       aria-label='Search'
   ╰────
  help: Remove the redundant role `combobox` from the element `input`.

  × jsx-a11y(no-redundant-roles): The `header` element has an implicit role of `banner`. Defining this explicitly is redundant and should be avoided.
    ╭─[App.jsx:16:13]
 15 │   return (
 16 │     <header role='banner' aria-label='Editor topbar'>
    ·             ─────────────
 17 │       Topbar
    ╰────
  help: Remove the redundant role `banner` from the element `header`.

Found 0 warnings and 2 errors.
Finished in 16ms on 1 file with 92 rules using 16 threads.

Why false positives

<input>

  • A plain <input> has implicit role textbox (par. 3.5.76).
  • The implicit role is only combobox when the input has a list attribute pointing at a <datalist> (par. 3.5.77).

The rule currently treats combobox as redundant at all times. eslint-plugin-jsx-a11y returns textbox for this case and never combobox.

This also makes the standard ARIA 1.2 combobox pattern un-lintable, because removing the role then triggers role-supports-aria-props for all the combobox ARIA attributes due to a missing role="combobox".

<header>

ARIA in HTML:

header

If not a descendant of an article, aside, main, nav or section element, or an element with role=article, complementary, main, navigation or region then role=banner

Otherwise, role=generic

This condition is ancestor-dependent and can't be determined from a single JSXOpeningElement.

eslint-plugin-jsx-a11y omits header and similar elements, likely for this reason.

Suggested fixes

  • <input>: only return combobox when a list attribute is set, otherwise return textbox.
  • <header> (and <footer>, <main>, <address>): remove from the check since they're ancestor dependent.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Fields

    Priority

    None yet

    Effort

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions