Skip to content

chore: support elements not in tree for get/hasAriaValue#5177

Open
straker wants to merge 4 commits into
developfrom
aria-value-outside-tree
Open

chore: support elements not in tree for get/hasAriaValue#5177
straker wants to merge 4 commits into
developfrom
aria-value-outside-tree

Conversation

@straker

@straker straker commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Found this when tying to update our matches functions.

There's a few times when we traverse up the DOM tree (getComposedParent, just a loop, etc.) and we want to get an ARIA attribute from it (e.g. aria-hidden-focus-matches.js walks up the tree looking for any ancestor with aria-hidden). Currently it's a bit clunky to have to handle both elements that could or could not be part of the tree as getAriaValue assumes vNode, so you have to do something like this:

const vNode = getNodeFromTree(el);
const ariaHidden = vNode
  ? getAriaValue(vNode, 'aria-hidden', { lowercase: true })?.value
  : (el.getAttribute('aria-hidden') || '').toLowerCase();

This is also a problem if the element we want to look at is a custom element outside the tree, as we won't be able to look at the element internals of it.

This fixes that by allowing the two get/has aria value functions to fallback to DOM nodes if the node is not in the tree.

@straker straker requested a review from a team as a code owner June 16, 2026 18:13

@chutchins25 chutchins25 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.

Nice work — the nodeLookup normalization reads cleanly and the in-tree path stays behavior-preserving. One question on the idref(s) fallback in getAttributeValue (inline).

Comment thread lib/commons/aria/get-aria-value.js
chutchins25
chutchins25 previously approved these changes Jun 18, 2026

@chutchins25 chutchins25 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.

Approving — this resolves the getPropertyValue issue I flagged on the prior commit: getAttributeValue now passes node (not the stale, out-of-tree-undefined vNode) into the idref(s) empty-attribute fallback, and the new out-of-tree idref/idrefs property tests guard that path. The nodeLookup(node).domNode swap is behavior-preserving for in-tree and SerialVirtualNode inputs, and out-of-tree support reads cleanly.

One optional, non-blocking polish nit (no action required): in has-aria-value.js, hasInternalValue computes getElementInternals(domNode) before the prop check, so for ARIA attributes with no associated prop it does the full internals lookup on out-of-tree nodes only to discard it. Its sibling getInternalValue in get-aria-value.js short-circuits with if (!prop) return null; first. Reordering hasInternalValue to check prop first would match that and skip the wasted work — purely a consistency/micro-perf thing, fine to leave.

@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.

Left a suggestion. I'm okay with it either way.

Comment thread lib/commons/aria/has-aria-value.js
Comment thread lib/commons/aria/get-aria-value.js
const internalsValue = vNode.elementInternals[prop];
const internals = vNode
? vNode.elementInternals
: getElementInternals(domNode);

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.

Same here, need to put the feature flag gate in. Or maybe put that into getElementInternals directly?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We didn't want to put it directly into getElementInternals as it's used by the gather-internals script and that couldn't really use a global axe due to the extensions needing it.

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.

3 participants