Skip to content

feat(text): support form-associated custom element labels#5061

Open
Krishnachaitanyakc wants to merge 2 commits intodequelabs:developfrom
Krishnachaitanyakc:fix/elementinternals-label
Open

feat(text): support form-associated custom element labels#5061
Krishnachaitanyakc wants to merge 2 commits intodequelabs:developfrom
Krishnachaitanyakc:fix/elementinternals-label

Conversation

@Krishnachaitanyakc
Copy link
Copy Markdown

Summary

Updates the accessible name computation to support <label> elements associated with form-associated custom elements via ElementInternals.

  • nativeTextAlternative: Detects form-associated custom elements (those with static formAssociated = true that called attachInternals()) by checking for the labels property on the actual DOM node. When detected, adds labelText to the element's naming methods so the accessible name algorithm resolves associated <label> elements.
  • getExplicitLabels (in label-text.js): For custom elements with a labels NodeList (exposed via ElementInternals), returns the labels directly instead of querying the DOM by id. Includes deduplication to prevent double-counting when an implicit (wrapping) label is already part of actualNode.labels.

Test plan

  • Added unit tests for nativeTextAlternative covering:
    • Form-associated custom element with an explicit label
    • Custom element without formAssociated (should return empty)
    • Form-associated custom element without labels (should return empty)
  • Added unit tests for labelText covering:
    • Explicit label via for attribute on a custom element
    • Multiple explicit labels on a custom element
    • Implicit (wrapping) label on a custom element
    • Deduplication: wrapping label that is also an explicit label (no double text)
    • No labels associated (should return empty)
  • All local tests pass (test:jsdom, test:node, test:tsc)
  • ESLint passes (0 errors)
  • Prettier formatting verified
  • Build succeeds

Closes #5045

…le name computation

Update nativeTextAlternative to detect form-associated custom elements
(those with `static formAssociated = true` and `attachInternals()`) and
include labelText in their naming methods so the accessible name
algorithm can find associated <label> elements.

Update getExplicitLabels to use the `labels` NodeList exposed by
ElementInternals directly when available, and add deduplication in
labelText to prevent double-counting when the implicit label is already
included in `actualNode.labels`.

Closes issue dequelabs#5045
@Krishnachaitanyakc Krishnachaitanyakc marked this pull request as ready for review April 7, 2026 20:52
@Krishnachaitanyakc Krishnachaitanyakc requested a review from a team as a code owner April 7, 2026 20:52
Copy link
Copy Markdown
Contributor

@straker straker left a comment

Choose a reason for hiding this comment

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

Thanks for the pr. I'm not sure this works as expected though. I'm pretty sure the label and labels properties are only on the internals object and not the root element itself. This means actualNode.labels is always undefined. Trying out the following shows that's the case as #target.label and #target.labels is undefined.

<script>
customElements.define(
  'custom-input',
  class extends HTMLElement {
    static formAssociated = true;
    constructor() {
      super();
      this.internals_ = this.attachInternals();
    }
  }
);
</script>

<label for="target">Custom label</label>
<custom-input id="target"></custom-input>

@Krishnachaitanyakc
Copy link
Copy Markdown
Author

@straker Thanks for reviewing, good catch. the label and labels properties are only on the internals object.

I've updated the approach by using customElements.get(tagName)?.formAssociated instead, and label resolution falls through to the standard label[for=id] matching via findElmsInContext.

…elements

The labels property is only available on the ElementInternals object,
not on the element itself, so actualNode.labels is always undefined
for custom elements. Use customElements.get(tagName)?.formAssociated
for detection and fall through to standard label[for=id] matching
via findElmsInContext.
@straker
Copy link
Copy Markdown
Contributor

straker commented Apr 13, 2026

Thanks for the update. Unfortunately window.customElements.get(nodeName) won't work either as axe-core is used in browser extensions where the isolated javascript context that axe runs in won't have access to any custom element registries. It's for that reason we have an entire set of custom element tickets that have to be done in a specific order in order to support this in all environments.

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: Update the explicitLabel functions to support form associated labels

2 participants