fix: template-no-invalid-aria-attributes — skip custom elements (hyphenated tags)#2732
fix: template-no-invalid-aria-attributes — skip custom elements (hyphenated tags)#2732johanrd wants to merge 4 commits intoember-cli:masterfrom
Conversation
…enated tags) HTML custom elements (tags with a hyphen, per WHATWG valid-custom-element-name) define their own a11y contracts; they may intentionally use aria-* attributes whose validity depends on the component's shadow-DOM-mapped role, which ESLint cannot introspect. Our rule previously flagged aria-* on every tag, producing false positives for these patterns. Skip the check when node.tag is a custom element (lowercase + hyphen). Matches angular-eslint's valid-aria behavior. Ref: audit tracking PR #28 item G6.
Translates 94 cases from peer-plugin rules: - jsx-a11y aria-props - vuejs-accessibility aria-props - lit-a11y aria-unsupported-elements / valid-aria-* - @angular-eslint/template valid-aria Fixture documents parity after this fix: custom elements (hyphenated tags) now skip the check. jsx-a11y has no equivalent concept and would still flag `<app-custom aria-x="text">`, which is documented inline.
|
Closing after deeper audit. WhyThe premise — "custom elements have author-defined a11y contracts; ESLint can't introspect, so skip" — doesn't hold up against peer-plugin evidence:
Only one peer skips, and it uses a different mechanism (allowlist, not a hyphen heuristic). The other three — including the plugin specifically designed for web components — validate custom elements normally. In practice, If a real false positive emergesThe right response would be a config option like Closing this in favor of matching the majority peer behavior (validate all elements). No changes to master. |
ElementInternals— and can legitimately carryaria-*attributes whose validity depends on the element's internally-set default role. ESLint cannot introspect that role.aria-*on every tag, including custom elements, producing false positives for patterns that work correctly at runtime.Fix: skip the check when
node.tagis a custom element (lowercase + hyphen heuristic).Heuristic vs. full spec
The WHATWG valid-custom-element-name grammar has more nuance than "lowercase + hyphen":
annotation-xml,color-profile,font-face,font-face-src,font-face-uri,font-face-format,font-face-name, andmissing-glyphare NOT valid custom element names despite containing hyphens.This PR's check is
lowercase + includes('-'), which over-accepts the reserved names. In practice these SVG/MathML legacy names rarely appear witharia-*in Ember templates, so the over-acceptance is acceptable. Worth a docstring note in the rule.Peer plugin behavior — verified in source
The prior claim "Matches angular-eslint's
valid-ariabehavior" was imprecise:valid-aria.ts:48-54getDomElements()(aria-query'sdomkeys). Custom elements are excluded because they're not in the allowlist, not via a hyphen heuristic. Same outcome for hyphenated tags; diverges on non-hyphenated unknown tags (e.g.<foo>— angular skips, our rule would still check).aria-props.js:39-57aria-*attribute on every element. No custom-element skip. (Reasonable — JSX doesn't directly model hyphenated tags.)aria-props.tsaria-attrs.js:37-60isInvalidAriaAttribute. AnisCustomElement.jshelper exists in the repo but is not used by aria-attrs. No custom-element skip. (Notable given lit-a11y targets Lit components, which ARE custom elements.)So the custom-element skip aligns us with angular-eslint in outcome for the hyphenated-tag case, but the three other peers all validate custom elements. We're the second plugin (after angular-eslint) to carve them out.
The "shadow-DOM-mapped role" phrasing in the original description is imprecise — the actual mechanism for author-defined roles on custom elements is
ElementInternals. Updated here.Audit fixture
Translated peer-plugin test fixture at
tests/audit/aria-props/peer-parity.js. Not wired into the default test run.