[WICG/webcomponents] [scoped-registries] How does customElements.upgrade() work? (Issue #1001)

Right now the global registry's `customeElemets.upgrade()` is the only way to upgrade a disconnected tree. With scoped registries, we will now have different registries each with an `upgrade()` method. We have to define how they work.

First, some goals:

- We can't break existing code
- We want existing calls to `.upgrade()` to do the "right" thing if elements in the subtree start using scoped registries.

This brings up a question of user intent. There are potentially two ways to interpret the current _intent_ of a `customElements.upgrade(tree)` call:
1. Upgrade all the elements that are defined in the global registry
2. Upgrade all the elements that are defined in any registry

These are ambiguous at the moment because there is currently only the one global registry.

There seem to me to be a couple of options of how to handle `upgrade()`. Let's consider how they work on a tree structure like this:

```html
<div>
  <x-a>
    #shadowroot (global registry)
      <x-b>
        #shadowroot (scoped registry)
          <x-c>
            #shadowroot (global registry)
              <x-d>
</div>
```

And let's assume that this structure is create in such a way that `<x-a>`, `<x-b>`, and `<x-d>` are defined in the global registry after the tree is created, and somehow `<x-c>` is defined in `<x-b>`'s scoped registry _after_ `<x-b>`'s shadow root is created.

This might be contrived and a very rare way to build a tree, but it's possible and I think shows the limit of the question we have to answer.

The question is what happens if someone calls:

```ts
customElements.upgrade(x_a);
```

1. Upgrade only the elements defined in the global registry.

    This may seem like the simplest approach, but it could break some cases where `x-c` and other elements need to interact (via events, etc). I would presume it would upgrade nested shadow roots using the global registry, including those nested in scoped-registry using roots like `x-c`'s.
    
    Presumably with this option, a scoped upgrade call (ie, `this.shadowRoot.customElements.upgrade(this.shadowRoot)`) would only upgrade definitions in that registry, in any shadow root in the tree using that registry, and not elements defined in the global registry.
    
2. Upgrade all elements.

    This might capture the intent of the call better, and results in a maximally functioning subtree.
    
    One way to do this would be to say that all registries have the same behavior for `.upgrade()` - that it's roughly equivalent to having a static `CustomElementRegistry.upgrade()` method.
    
It might be rare to be in a situation where the answer here matters. I think generic code that needs to call `.upgrade()` is also probably creating the disconnected subtree, and in order to use scoped registries must already be creating the subtree with one of the scoped element creation APIs.

Still, I think option 2 probably matches user intent better. I'm trying to think of a case where that behavior _isn't_ what you want - where you only want definitions from a single registry to upgrade.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/WICG/webcomponents/issues/1001
You are receiving this because you are subscribed to this thread.

Message ID: <WICG/webcomponents/issues/1001@github.com>

Received on Tuesday, 18 April 2023 17:24:23 UTC