Skip to content

fix: support form-associated custom elements in isLabelable - #1387

Open
koding88 wants to merge 1 commit into
testing-library:mainfrom
koding88:fix/form-associated-custom-element-labelable
Open

koding88 wants to merge 1 commit into
testing-library:mainfrom
koding88:fix/form-associated-custom-element-labelable

Conversation

@koding88

@koding88 koding88 commented Aug 26, 2026 •

Copy link
Copy Markdown

Fixes #1343

Summary

Adds a formAssociated check to isLabelable and a for/id fallback in getRealLabels so getByLabelText can find form-associated custom elements.

Background

The HTML spec lists form-associated custom elements as labelable, but isLabelable only checked built-in tag names:

/BUTTON|METER|OUTPUT|PROGRESS|SELECT|TEXTAREA/.test(element.tagName) ||
(element.tagName === "INPUT" && element.getAttribute("type") !== "hidden")

A custom element with formAssociated = true should be targetable by <label for>, but getByLabelText threw "non-labellable" for it.

getRealLabels also needed a fallback because label.control is null for custom elements in jsdom (only populated for built-in form controls). In real browsers element.labels is defined for form-associated custom elements and the early return handles it. The fallback matches by label.htmlFor === element.id to cover jsdom.

Verification

  • npm test: 669 tests pass (29 suites).
  • npm run lint: clean.

formAssociated custom elements are labelable per HTML spec but
isLabelable only checked built-in tag names. Add formAssociated
check so getByLabelText finds them.

Also add for/id fallback in getRealLabels for environments where
label.control is null for custom elements (e.g. jsdom).
Copilot AI lite review requested due to automatic review settings August 26, 2026 05:50
@codesandbox-ci

Copy link
Copy Markdown

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 181abe4:

Sandbox Source
react-testing-library-examples Configuration

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR updates label association logic so getByLabelText can work with form-associated custom elements by treating them as labelable and providing a for/id fallback when label.control is not implemented (e.g. in jsdom).

Changes:

  • Extend isLabelable to recognize form-associated custom elements.
  • Add a for/id fallback in getRealLabels when label.control cannot be used.
  • Add/extend tests covering custom element label behavior via getByLabelText.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/label-helpers.ts Adds FACE detection to isLabelable and a for/id fallback path in getRealLabels.
src/tests/label-helpers.js Adds tests intended to cover labelability of custom elements.
src/tests/element-queries.js Adds an integration-style query test for custom elements via getByLabelText.

馃挕 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/label-helpers.ts
Comment on lines 60 to 64
/BUTTON|METER|OUTPUT|PROGRESS|SELECT|TEXTAREA/.test(element.tagName) ||
(element.tagName === 'INPUT' && element.getAttribute('type') !== 'hidden')
(element.tagName === 'INPUT' &&
element.getAttribute('type') !== 'hidden') ||
(element as HTMLElement).formAssociated === true
)
Comment on lines +9 to +18
test('form-associated custom elements are labelable', () => {
const element = document.createElement('my-input')
element.formAssociated = true
expect(getRealLabels(element)).toEqual([])
})

test('custom elements without formAssociated are not labelable', () => {
const element = document.createElement('my-input')
expect(getRealLabels(element)).toEqual([])
})
Comment on lines +1195 to +1203
test('can get a form-associated custom element by label', () => {
const {getByLabelText} = renderIntoDocument(`
<label for="custom-input">Custom Label</label>
<my-input id="custom-input"></my-input>
`)
const el = document.getElementById('custom-input')
el.formAssociated = true
expect(getByLabelText('Custom Label')).toBe(el)
})

This branch has not been deployed

No deployments
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.

isLabelable does not support custom elements with formAssociated = true

2 participants