Skip to content

BUGFIX: template-no-invalid-role — support DPUB/Graphics-ARIA and role-fallback lists#2729

Draft
johanrd wants to merge 6 commits intoember-cli:masterfrom
johanrd:fix/invalid-role-aria-query
Draft

BUGFIX: template-no-invalid-role — support DPUB/Graphics-ARIA and role-fallback lists#2729
johanrd wants to merge 6 commits intoember-cli:masterfrom
johanrd:fix/invalid-role-aria-query

Conversation

@johanrd
Copy link
Copy Markdown
Contributor

@johanrd johanrd commented Apr 21, 2026

Two related fixes in one rewrite. Both were false positives that rejected documented-valid ARIA patterns.

1. DPUB-ARIA and Graphics-ARIA roles

  • Premise: DPUB-ARIA and Graphics-ARIA are W3C Recommendations that extend WAI-ARIA with doc-* (40+ roles) and graphics-* (3 roles) tokens. aria-query indexes them under its roles map.
  • Problem: Our hand-maintained VALID_ROLES (~90 tokens) covered only WAI-ARIA base roles. role="doc-abstract", role="graphics-document", etc., were flagged as invalid.

Fix: derive VALID_ROLES from aria-query's concrete (non-abstract) role keys. Covers ~127 roles automatically.

A small ARIA 1.3 draft allowlist (associationlist, associationlistitemkey, associationlistitemvalue, comment, suggestion) is kept inline because aria-query doesn't yet ship those.

2. Whitespace-separated role fallback lists

  • Premise: ARIA 1.2 §4.1 WAI-ARIA Rolesrole is a list of tokens. The UA picks the first one it recognises; the others are fallbacks.
  • Problem: Our rule treated role="tabpanel row" as one opaque value — VALID_ROLES.has("tabpanel row") is false — and flagged the whole string as invalid.

Fix: split on whitespace, validate each token. The error message now names the first offending token (Invalid ARIA role 'foobar') rather than the whole string.

Before/after

HTML Before After
<div role="doc-abstract"> invalid valid
<svg role="graphics-document"> invalid valid
<div role="tabpanel row"> invalid (whole string) valid
<section role="doc-appendix doc-bibliography"> invalid (whole string) valid
<div role="tabpanel row foobar"> invalid (whole string as role name) invalid (specifically: 'foobar')

Three existing invalid tests updated to reflect the per-token error message; ten new valid tests cover the fixes.

Prior art

Plugin Rule Notes
jsx-a11y aria-role Uses aria-query's roles.keys() directly; .split(' ') the value and checks each token against the set of concrete roles.
vuejs-accessibility aria-role Same pattern as jsx-a11y.
lit-a11y aria-role No whitespace split; passes the full role string to isConcreteAriaRole, so multi-token fallback lists like role="tabpanel row" fail.

@angular-eslint/template's valid-aria rule validates aria-* attribute names and values rather than role tokens, so it has no direct analog for the fallback-list fix.

Audit fixture

Includes translated peer-plugin test fixture at tests/audit/aria-role/peer-parity.js documenting our rule's behavior relative to jsx-a11y / vuejs-accessibility / lit-a11y. Not wired into the default test run; intended for behavioral-parity auditing.

johanrd added 3 commits April 21, 2026 07:47
…pport DPUB-/Graphics-ARIA and role-fallback lists

Two related fixes, shared rewrite.

1. Replace the hand-maintained VALID_ROLES (~90 WAI-ARIA 1.2 tokens)
   with a derived list from aria-query (concrete — non-abstract — role
   keys), plus a small ARIA 1.3 draft-role allowlist that aria-query
   doesn't yet ship.

   Effect: DPUB-ARIA roles (doc-abstract, doc-chapter, …) and
   Graphics-ARIA roles (graphics-document, graphics-object,
   graphics-symbol) are no longer flagged as invalid.

2. Split the role value on whitespace before validating. A role
   attribute is a list of tokens per ARIA 1.2 §5.4 (role fallback).
   Each token must individually be valid.

   Effect: role="tabpanel row", role="doc-appendix doc-bibliography",
   and role="graphics-document document" now pass; role="tabpanel
   row foobar" flags the first invalid token ("foobar") instead of
   rejecting the whole string as one opaque role name.

Error message now names the specific offending token. Three existing
invalid tests updated accordingly (previously expected the whole
string; now the specific token).

Ten new valid tests cover DPUB/Graphics and the fallback-list shape.
Translates 32 cases from peer-plugin rules:
  - jsx-a11y aria-role
  - vuejs-accessibility aria-role
  - lit-a11y aria-role

Fixture documents parity after this fix:
  - DPUB-ARIA and Graphics-ARIA roles accepted (via aria-query).
  - Space-separated role tokens accepted when all are valid, and the
    invalid-token variant names the specific offending token.

Remaining divergences (case-insensitive comparison, empty-string role
not flagged) are annotated inline.
…kens

`associationlist`, `associationlistitemkey`, and `associationlistitemvalue`
are not present in the current WAI-ARIA 1.3 editor's draft
(https://w3c.github.io/aria/). Earlier commit listed all five as draft
tokens; only `comment` and `suggestion` are actually proposed. Drop the
three phantom tokens and the tests that accepted them as valid.

With this change the rule now correctly flags `role='associationlist'`
and siblings as invalid, matching peer behavior (jsx-a11y, vue-a11y,
lit-a11y all reject them).
johanrd added 2 commits April 22, 2026 14:22
…Copilot review)

The PR body claimed the ARIA 1.3 draft allowlist covers 5 roles (associationlist,
associationlistitemkey, associationlistitemvalue, comment, suggestion). The
code only listed 2 ('comment', 'suggestion'); the gap was invisible because
no tests exercised any of them. Verified against aria-query 5.3.2:
roles.has() returns false for all 5, so all 5 belong in the inline allowlist
until aria-query catches up.

Also: when reporting presentation/none on a semantic element, include the
offending token in the message data instead of the raw role attribute
string — avoids surfacing e.g. 'presentation listbox' when only
'presentation' is the issue.

Tests: add 5 valid cases in each of the gts and hbs blocks covering all
ARIA 1.3 draft roles.
@johanrd johanrd force-pushed the fix/invalid-role-aria-query branch from 49fafaa to 7e45da3 Compare April 22, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant