Skip to content

feat(rules): support ARIA element internals properties#5168

Open
straker wants to merge 5 commits into
developfrom
internals-rules
Open

feat(rules): support ARIA element internals properties#5168
straker wants to merge 5 commits into
developfrom
internals-rules

Conversation

@straker

@straker straker commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Updates the rules directory to use the new getAriaValue function where it makes sense. Only the JS match files were reviewed; JSON rule definitions have no ARIA attr access.

Here's a report of the full directory (JS files only):

  • rules/autocomplete-matches - aria-readonly and aria-disabled → getAriaValue with { lowercase: true } (both are boolean type); removed the now-redundant .toLowerCase() calls on the comparison
  • rules/aria-allowed-attr-matches - iterates over attrNames, no direct .attr('aria-*') call
  • rules/aria-has-attr-matches - checks for presence of any aria attr via attrNames, not a value lookup
  • rules/bypass-matches - checks for links and headings, no ARIA attr access
  • rules/color-contrast-matches - checks visibility, no ARIA attr access
  • rules/identical-links-same-purpose-matches - computes accessible names, no ARIA attr access
  • rules/inserted-into-focus-order-matches - checks tabindex, not an ARIA prop
  • rules/label-matches - checks element type and role, no direct aria attr value access
  • rules/landmark-has-body-context-matches - checks role, not an ARIA prop
  • rules/no-autoplay-audio-matches - checks media attributes, no ARIA attr access
  • rules/no-empty-role-matches - checks role attr, not an ARIA prop
  • rules/no-negative-tabindex-matches - checks tabindex, not an ARIA prop
  • rules/no-role-matches - checks role attr, not an ARIA prop

Closes: #5150

Updates autocomplete-matches.js to use getAriaValue for aria-readonly
and aria-disabled checks so that values set via ElementInternals are
also respected.
@straker straker requested a review from a team as a code owner June 15, 2026 21:58
straker added 4 commits June 16, 2026 09:08
- aria-hidden-focus-matches: shouldMatchElement used el.getAttribute('aria-hidden')
  directly on a DOM node; convert to getAriaValue via getNodeFromTree with
  fallback to getAttribute when the node is not in the axe virtual tree
- color-contrast-matches: control.getAttribute('aria-labelledby') used to
  check which controls reference an ancestor; convert to vNode.attr() for the
  HTML attribute case, and getResolvedRefs for the property/internals case
  (where the attribute string is absent but element refs are set)
…nternals

Adds a full integration test verifying that a focusable element inside
a [aria-hidden=true] container whose ancestor has aria-hidden=true set
via elementInternals is excluded from the rule — no violations.
…on/rules

Add a testutils-element with aria-hidden via elementInternals containing
a focusable [aria-hidden=true] div. With the fix the inner element is
excluded by the matches function (ancestor internals aria-hidden detected)
so no new violation appears. Without the fix it would be a violation,
causing 'should not return other results' to fail.

@WilcoFiers WilcoFiers left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just needs to be updated to 5177

Comment on lines +17 to +20
// the composed parent could or could not be included in the tree so we'll need to handle either case
const ariaHidden = vNode
? getAriaValue(vNode, 'aria-hidden', { lowercase: true })?.value
: el.getAttribute('aria-hidden');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chutchins25

chutchins25 commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Heads up: the audit report in the PR description looks out of sync with the actual diff.

The description lists autocomplete-matches as the converted file and marks both color-contrast-matches and (implicitly) aria-hidden-focus-matches as having no ARIA attr access. But the diff actually converts:

  • lib/rules/aria-hidden-focus-matches.jsaria-hiddengetAriaValue
  • lib/rules/color-contrast-matches.jsaria-labelledbygetResolvedRefs / getAriaValue

…and doesn't touch autocomplete-matches. Worth refreshing the report so it matches what shipped before merge.

(Also updated the issue trailer — this is the rules/*-matches conversion, so it was pointing at the wrong issue. For history: changed from Refs: https://github.com/dequelabs/axe-core/issues/5142 to Closes: https://github.com/dequelabs/axe-core/issues/5150.)

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.

ElementInternals: convert lib/rules/*-matches to getAriaValue/hasAriaValue

3 participants