Skip to content

Conversation

@ja-y-son
Copy link
Contributor

@ja-y-son ja-y-son commented Dec 2, 2025

Fixing #1429 to make sure element is getting the correct scoped custom element registry upon adoption. This PR also includes the concept that will be defined in whatwg/html#12000 (keep custom element registry null).

(See WHATWG Working Mode: Changes for more details.)


Preview | Diff

dom.bs Outdated
<a for=Element>custom element registry</a> is null or is equal to <var>document</var>'s
<a>effective global custom element registry</a>, then set <var>inclusiveDescendant</var>'s
<a for=Element>custom element registry</a> to <var>inclusiveDescendant</var>'s
<a for=tree>parent</a>'s <a for=Element>custom element registry</a>.
Copy link
Member

Choose a reason for hiding this comment

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

Why is this not using the "effective global custom element registry" strategy discussed? It's not clear to me this is the same or why we need to be looking at document at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated to use "effective global custom element registry" strategy as discussed. Was trying to see if I could get the point across with another approach but it seems like "effective global custom element registry" is still the better way to go. Lmk if I'm missing anything on this idea.

Copy link
Member

@annevk annevk left a comment

Choose a reason for hiding this comment

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

This looks good to me. We'll need tests next.

For the tests I'd like us to exercise some of the more complicated scenarios with some nodes having been assigned registries and others not, etc.

@ja-y-son
Copy link
Contributor Author

ja-y-son commented Dec 2, 2025

Just added some tests but I haven't fully verified them yet. Feel free to take a look.

@ja-y-son
Copy link
Contributor Author

ja-y-son commented Dec 4, 2025

@annevk Want to verify that this is the expected behavior from this change on effective gloabl registry. Consider this test case from adoption.window.js

test(t => {
  const contentDocument = document.body.appendChild(document.createElement('iframe')).contentDocument;
  t.add_cleanup(() => contentDocument.defaultView.frameElement.remove());
  const element = document.createElement('div');
  assert_equals(element.customElementRegistry, customElements);

  const scoped = new CustomElementRegistry();
  const scopedElement = contentDocument.createElement('div', { customElementRegistry: scoped });
  contentDocument.body.appendChild(scopedElement);
  assert_equals(scopedElement.customElementRegistry, scoped);
  scopedElement.appendChild(element);
  assert_equals(element.customElementRegistry, contentDocument.customElementRegistry);
}, "Adoption with global registry into a scoped registry");

Given that now we look at the parent's registry's effective global registry, the last assert of the test should probably be

assert_equals(element.customElementRegistry, null);

given that the parent is using a scoped registry.
Is this expected? Or we want it to keep getting global registry for this element? It feels a bit odd that it originally has a global registry but after adoption it goes to null registry. Perhaps we should make sure that non-null registry element shouldn't get null registry after adoption (unless there are no global registry available)?

@annevk
Copy link
Member

annevk commented Dec 4, 2025

Yeah, I suppose distinguishing those cases would be better. I doubt anyone is going to run into this in practice, but we might as well make it nice.

dom.bs Outdated
Comment on lines 6099 to 6110
<li>
<p>Otherwise, set <var>registry</var> to the
<a>effective global custom element registry</a> of the result of
<a for=/>looking up a custom element registry</a> given <var>inclusiveDescendant</var>'s
<a for=tree>parent</a>.

<ol>
<li><p>If <var>inclusiveDescendant</var>'s <a for=Element>custom element registry</a> is
non-null and <var>registry</var> is null, set <var>registry</var> to
<var>document</var>'s <a for=Document>custom element registry</a>'s
<a>effective global custom element registry</a>.
</ol>
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand this. If you mean for this to only apply in the Otherwise branch you need to nest the first bit of the Otherwise branch as well.

@ja-y-son
Copy link
Contributor Author

ja-y-son commented Dec 5, 2025

I think I made it unnecessarily complicated in the previous iteration. Given that our main goal is that global registry element shouldn't become null registry during adoption, I think we can simply include this category (global registry) to use document's registry's effective global registry, so it wouldn't be getting null from parent. Does this make sense? Or perhaps I'm missing something here.

Copy link
Member

@annevk annevk left a comment

Choose a reason for hiding this comment

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

Yeah I think this works. I'll re-review on Monday to be sure. If @sorvell, @rniwa, and maybe @keithamus could have a look as well that'd be great.

(Checking inclusiveDescendant's custom element registry again bothers me a little bit, but I don't see a good way out of that. I also want to double check the "DocumentFragment but not ShadowRoot" language.)

ja-y-son and others added 2 commits December 7, 2025 20:03
Co-authored-by: Anne van Kesteren <annevk@annevk.nl>
@ja-y-son
Copy link
Contributor Author

ja-y-son commented Jan 4, 2026

@annevk Went through this PR again and I think it still works. Do we want to merge this PR first while wrapping up web-platform-tests/wpt#56423

dom.bs Outdated

<li><p>If <var>registry</var> <a>is a global custom element registry</a>, then set
<var>registry</var> to <var>document</var>'s <a>effective global custom element registry</a>.
<var>registry</var> to <var>document</var>'s <a for=Document>custom element registry</a>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
<var>registry</var> to <var>document</var>'s <a for=Document>custom element registry</a>
<var>registry</var> to <var>document</var>'s <a for=Document>custom element registry</a>'s

(might have to rewrap)

dom.bs Outdated
<li><p>If <var>inclusiveDescendant</var>'s <a for=Element>custom element registry</a> is
non-null, <var>inclusiveDescendant</var>'s <a for=tree>parent</a> is null, or
<var>inclusiveDescendant</var>'s <a for=tree>parent</a> is a {{DocumentFragment}} but not
a {{ShadowRoot}}, then set <var>registry</var> to <var>document</var>'s
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
a {{ShadowRoot}}, then set <var>registry</var> to <var>document</var>'s
a {{ShadowRoot}} <a for=/>node</a>, then set <var>registry</var> to <var>document</var>'s

I might actually want to define exclusive DocumentFragment for this. Similar to what we have for Text nodes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could you elaborate on what you meant by define exclusive DocumentFragment?

Copy link
Member

Choose a reason for hiding this comment

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

I'm happy to take care of that but if you want to take a stab at it you'd have to define something equivalent to https://dom.spec.whatwg.org/#exclusive-text-node for DocumentFragment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added the definition for exclusive document fragment. Let me know if I captured what you thought correctly.

dom.bs Outdated
<dt><dfn export for=Element>custom element registry</dfn>
<dd>Null or a {{CustomElementRegistry}} object.

<dt><dfn export id=concept-element-keep-custom-elemenet-registry-null for=Element>keep custom element registry null</dfn>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
<dt><dfn export id=concept-element-keep-custom-elemenet-registry-null for=Element>keep custom element registry null</dfn>
<dt><dfn export for=Element>keep custom element registry null</dfn>

We don't do hardcoded IDs for new concepts. Use the generated ID.

@annevk
Copy link
Member

annevk commented Jan 7, 2026

Also, now that "keep custom element registry null" is part of this PR, it depends on whatwg/html#12000 so we should mention that in the commit message and get that PR finished as well.

@ja-y-son
Copy link
Contributor Author

ja-y-son commented Jan 8, 2026

I updated the commit message so it mentions the new concept that will be defined in whatwg/html#12000. I'll prioritize getting this adoption logic PR landed and will for sure get the attribute PR finished next. Let me know if you prefer me to take "keep custom elemetn registry null" idea out of this PR for now; I can also land this PR without the concept and put it together with attribute PR.

@annevk
Copy link
Member

annevk commented Jan 8, 2026

Let's keep it out of this PR then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants