[WICG/webcomponents] Scoped Custom Element Registry: Moving elements with shadow roots between documents (#907)

_follow up from https://github.com/WICG/webcomponents/issues/895_

This issue has been discussed briefly multiple times (#716, https://github.com/WICG/webcomponents/pull/865#issuecomment-700336090), without a clear consensus. We could not get to it during the recent F2F meeting, and instead we decided to try to resolved via an issue.

After reviewing the current state of the spec, and current implementations, I now believe that what @rniwa was saying was correct (not a surprise). Scoped Custom Element Registries are fundamentally incompatible with moving custom element instances between documents. Here is my take on this:

## Current state of affairs

1. Moving custom element instances between documents is not very common, but still possible. After creating a custom element somehow, in another document, the element can be moved into a new document without too much hazard (note: it is not hazard free, but the risk is pretty small).

2. Moving custom element declarations between documents is not disallowed, but the creation of instances via document.createElement will throw, and creation of those via `new` is not different from point 1.

3. Instances moved are hazardous because they could incur on invalid operations, e.g.: an instance that when connected, attempt to populate its shadow root (which is a common operation) where elements used by the shadow are not registered in the destination document (new owner document).

4. Invariant: Any element created from markup or `document.createElement` must be registered in the document itself, and must produce an instance of the corresponding HTMLElement.

## The problem with Scoped Registry

When an instance is moved (see 3), and any element created from markup or `shadowRoot.createElement`, from that point on, must produce an instance of the ownerDocument's corresponding HTMLElement. This is the fundamental problem, because that registry was most likely created and populated by the declaration, or instantiation of the custom element. E.g. of such broken code:

```js
const registry = new CustomElementRegistry();
registry.define('x-child', SomeConstructor);
export class extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({ mode: 'open', registry });
    }
    connectedCallback() {
        this.shadowRoot.innerHTML = '<x-child></x-child>'
    }
}
```

## Proposed solution

This proposed solution assumes that moving custom elements with scoped registries is going to be a very very rare situation:

A. Use the same protection mechanism used today by the global registry. Fail with `A newly constructed custom element belongs to a wrong document` (Safari) or a similar error when needed.

B. Allow a new registry to be set into an existing shadow root, that way the authors expecting elements to be moved between documents can do the extra work of redefining the registry for their necessary elements when an instances are moved around.


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

Received on Tuesday, 10 November 2020 00:00:10 UTC