Skip to content

Every built-in element is :defined - #193

Merged
jdalton merged 3 commits into
dperini:masterfrom
jdalton:fix/defined-built-ins
Sep 7, 2026
Merged

jdalton merged 3 commits into
dperini:masterfrom
jdalton:fix/defined-built-ins

Conversation

@jdalton

@jdalton jdalton commented Sep 4, 2026 •

Copy link
Copy Markdown
Collaborator

Fix

Match built-in HTML, SVG, and MathML elements with :defined. Use native custom-element state when available, with a registry fallback for hosts that cannot provide it. Keep native-matcher reentry guarded.

Tests

Focused tests cover ordinary elements, autonomous custom elements, customized built-ins, upgrades, cached queries, and native state after is-attribute changes. A Chromium test compares results before and after install().

413 Node tests and all 43 WPT pages pass. Type checks, lint, and the Chromium comparison pass. Combined coverage passes every unchanged threshold.

@jdalton
jdalton force-pushed the fix/defined-built-ins branch 2 times, most recently from e50f059 to bb2ea11 Compare September 5, 2026 02:48
@jdalton

jdalton commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator Author

This one sits with #190 and #191 and #192, which touch the conformance fixes found by comparing against Chromium.

They do not depend on each other. All seventeen in the series cherry-pick onto master in any order, and I checked that in both directions, so any one of these can land alone. The order below is the one they read best in:

  • #190 makes :enabled the complement of :disabled, fieldsets included.
  • #191 anchors the :required and :optional tests, and lets :optional take a button.
  • #192 makes a fieldset :valid when none of its controls is invalid.
  • #193 makes every built-in element :defined.

':defined' asks the custom element registry about the candidate's tag name and requires an instanceof match, so it matches upgraded custom elements and nothing else. Every built-in element is defined; only a custom element can be undefined, and only until a definition exists and it has been upgraded. Browsers read it off the element's custom element state, where uncustomized and custom are the two that count as defined. https://github.com/chromium/chromium/blob/155.0.8041.1/third_party/blink/renderer/core/dom/element.h#L1201
 The test reads the hyphen in the name first, which is what makes a name a custom element name, and asks for the 'is' attribute only when there is none, so an ordinary element costs one string scan.

References:

- Spec: https://dom.spec.whatwg.org/#concept-element-defined — uncustomized and custom are the two states that count as defined
- Spec: https://html.spec.whatwg.org/#custom-elements-core-concepts — what makes a name a custom element name
- Chromium: https://github.com/chromium/chromium/blob/155.0.8041.1/third_party/blink/renderer/core/dom/element.h#L1201 — the state read, with the same spec link in its own comment
- Chromium: https://github.com/chromium/chromium/blob/155.0.8041.1/third_party/blink/renderer/core/css/selector_checker.cc#L3139 — ':defined' is that and nothing else
- MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/:defined
@jdalton
jdalton force-pushed the fix/defined-built-ins branch from ae6aada to 6b2375a Compare September 6, 2026 11:40
@jdalton
jdalton merged commit 63c05fb into dperini:master Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant