WICG / webcomponents

Web Components specifications

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[scoped-registries] Finding a definition for disconnected elements

sorvell opened this issue · comments

Assuming the behavior described in the explainer's Finding a custom element definition section, consider the following.

  1. Define x-foo in the global and a scoped registry.
  2. In a shadowRoot using that registry, create an element:el = shadowRoot.createElement('div').
  3. Now create and x-foo via innerHTML: el.innerHTML = '<x-foo></x-foo>'.

I believe this results in an x-foo element upgraded via the global registry, and that behavior seems surprising and unexpected. I would expect in that case the x-foo element would use the scoped registry definition.

Perhaps this could be addressed if elements had an ownerRegistry setting (similar to ownerDocument) that could be used to lookup the correct definition.

The reason why the proposal doesn't have elements remember their registry is because the Chrome DOM team at the time was very reluctant to adding another reference to all elements to point to the registry due to memory concerns. That changed the design to dynamically looking up the registry by using the element's current root node if the root node is a ShadowRoot.

Maybe there's a pattern where only root node elements created within a scope need to store their registry, and all other elements don't store a registry. I'm not sure if most DOM implementations put some references into a dynamic map (I think Blink calls this "rare data" maybe?), but that could reduce the memory overhead.

Thoughts @mfreed7 @rniwa?

I would expect in that case the x-foo element would use the scoped registry definition.

100%

I can't think of how this can be allowable. It's going to throw many people off.

After discussion at the April F2F.

Implementor consensus seemed to point to a concern over memory use related to the need to track an element's "active registry."

An alternate proposal that seemed more feasible was to add registry to the options for setHTML. For example:

  const d = shadowRoot.createElement('div');
  d.setHTML(`<x-foo></x-foo>`, {registry: shadowRoot.registry});

And effectively this would do the same thing as:

  setHTML = (node, html, registry) => {
    const template = document.createElement('template');
    template.innerHTML = html;
    registry.upgrade(template.content);
    node.replaceChildren(...template.content.childNodes);
  }