Scoped Custom Element Registries #716
Comments
Questions:
Missing features
RecommendationBased on those two possible missing features, and extensibility point of view, it is probably easier to find an API that delegates part of the resolution to user-land, and let users to implement the hierarchical/resolution algo. e.g.: class MyFoo extends HTMLElement {}
// lookup must return a registry
function lookup(registry, name) {
if (name === 'my-bar') {
return customElements; // delegate the lookup to another known registry (in this case the global registry)
}
if (name === 'my-baz') {
registry.define('my-baz', class extends HTMLElement {}); // define inline
} else {
// import `name` component, and define it in `register` when it is ready...
}
return registry;
}
const myRegistry = new CustomElementRegistry(lookup);
myRegistry.define('my-foo', MyFoo); // you can still prime the registry This will require effectible a new constructor with a single argument, nothing else. Or could potentially be fold into Wish List
|
hey @justinfagnani, this is the comment that I've mentioned today, let's chat about this tomorrow, I can explain more. |
What happens in
This seems like it could be useful for some sort of framework, but would definitely be nice to have a default (that just looks in the parent scope) so that the end user can just do something perhaps as easy as const myRegistry = new CustomElementRegistry()
myRegistry.define('my-foo', MyFoo);
this.root = this.attachShadow({mode: 'open', registry: myRegistry}) which causes lookup to look in the parent scope (parent shadow root) when the element name is not found in the current registry. Just tossing in a syntax idea: this.root = this.attachShadow({mode: 'open', registry: true})
this.root.define('my-foo', MyFoo); or maybe just simply: this.root = this.attachShadow({mode: 'open'})
this.root.define('my-foo', MyFoo); // creates a registry internally on first use And for advanced use (f.e. defining lookup): this.root = this.attachShadow({mode: 'open'})
console.log(this.root.registry) // null
this.root.define('my-foo', MyFoo); // creates a registry on first use
console.log(this.root.registry) // CustomElementsRegistry
// ... and for advanced users:
this.root.registry.defineLookup(function() { ... })
// also use the registry directly:
this.root.registry.define('other-foo', OtherFoo) This way it's easier, yet still configurable for advanced cases. |
Oh! This is also a great opportunity to not require hyphens in element names of scoped registries! Maybe it's possible? |
@trusktr Although I really like the idea of hyphen-less names what would happen if you happen to upgrade an existing name? e.g. What on earth would happen in this situation: <link rel="stylesheet" src=".." />
<script>
class MyLink extends HTMLElement {
constructor() {
// Would this still be a proper link element?
// If so this clearly wouldn't work as HTMLLinkElement
// doesn't support attachShadow
this.attachShadow({ mode: 'open' })
}
}
window.customElements.define('link', MyLink)
</script> Now I think this could actually be resolvable by having a special element that must be included in head (similar to For example it might look something like this: <head>
<override element="link">
<override element="input">
<!-- Or maybe <override elements="link input">
</head>
<body>
<!-- link no longer works as a link tag but is just a plain html tag -->
<link rel="stylesheet" />
<!-- Neither does input -->
<input type="date">
<script>
...
customElements.define('input', MyCustomInput)
</script>
</body> Of course this doesn't explain what'd happen if I think it's simpler to keep this and #658 separate given that I don't think it's worth blocking scoped registries on a topic that I personally think is much more complicated than scoped registries. |
Just like with variable shadowing in practically any programming language, then in that case that const foo = "foo"
~function() {
const foo = "bar"
console.log(foo)
// is "foo" here the same "foo" as outside? Nope, not any more, we're in a new scope!
}() Same thing for elements! If you override a "variable" (in this case an element name) in the inner scope, then it is no longer what it was in the outer scope.
But, that's in global scope. Overriding should only be possible in non-global scope. Maybe, But then again, I don't like redundancy, I like things DRY. Imagine if this was required in JavaScript: const foo = "foo"
~function() {
override foo;
const foo = "bar"
console.log(foo)
}() I would not prefer a similar thing for HTML name scope. But, what if an HTML/CSS no-JS person looks at the markup? They might get confused? True! I would probably not want to do that, just like I don't override globals in JS. What it would really be useful for is, for example, coming up with new element names that don't already exist (like I find myself in situation where I'm forced to think of another word to add to a single-word component, just to appease the hyphen rule. Sometimes I do something dumb like So my specific argument isn't leaning towards overriding certain builtins, though I can imagine that if someone wanted to implement a "super Personally, I just want to use single words when I want to. |
Good point. That'd be great regardless of hyphen-or-not! |
This sounds the most important principle in the proposal, to understand the behaviors. It's a new comments
|
I'd like to ask, what is the desired approach of providing definitions of scoped custom elements? I have a number of use cases where shadow root is created, therefore scoped custom elements registry could be used, not for custom elements. Even for custom elements, it does not have to be exactly the same for every instance. In those cases, shadow dom is created by a separate entity and just employed by the host. I'd like to ask about a more declarative approach and defining elements closer to the markup that uses them, like: <template is="declarative-shadow-root"> to be stamped in different places.
<link rel="import" href="/path/to/my-element/definition.html">
or
<script src="/path/to/my-element/definition.js"></script>
or
<script type="module" src="/path/to/my-element/definition.html"></script>
or
<script type="module">
import {MyElement} from '/path/to/my-element/definition.js';
import.meta.scriptElement.getRootNode().customElements.define('my-element',MyElement);
</script>
<p>Shadow dom that's encapsulated, independent, and works exactly the same anywhere it's attached</p>
<my-element>scoped custom element, working in a scoped tree</my-element>
</template> The person who creates the markup for shadow dom is the one who knows best what elements need to be used. I believe, above approach would be intuitive, and should play well with declarative Shadow DOM. For the document tree, you can provide custom elements and scripts that work in its scope. I don't have to provide them by the entity who stamps the document - like browser or HTTP. It would be useful to be able to provide element definitions from within the shadow tree scope, that would be scoped to this tree and do not pollute the document. However, given the HTML Imports are dead, classic |
@tomalec one of the use cases we're trying to address is a large application that may not be able to guarantee that each tag name is used only once, whether because there are version conflicts, or because portions of the app are built and distributed separately. We see this with decentralized teams, or with applications with plug-in systems like IDEs. The pattern that would need to develop is that elements would be distributed without self-registering: export class MyElement extends HTMLElement {}
// no customElements.define() call The user of the element imports and defines the element in the registry it's using: import {MyElement} from './my-element.js';
const localRegistry = new CustomElementRegistry();
localRegistry.define('my-element', class extends MyElement {});
class MyContainer extends HTMLElement {
constructor() {
this.attachShadow({mode: 'open', customElements: localRegistry});
}
} This scopes the definition so it doesn't conflict with any other registration is the entire page. I prefer the imperative API as a start because it's an incremental change from current patterns and doesn't tie this proposal with with another. Tying the scope to the ShadowRoot is mainly because ShadowRoot is the one scoping mechanism we have in the DOM, and it makes sense that a scope will work for a number of things like CSS, element definitions, and DOM. If there's a situation where the shadow root creator and the registry owner are different, I suspect there will usually be a way to route the registry to or from the ShadowRoot creator to be able to get the registry to the right place. For any declarative feature we do have a problem of referencing values in JS. The current solution is exactly CustomElementRegistry: a global keyed object that's specced to be used as a lookup from a DOM value. In general I don't think we've identified a slam-dunk pattern for referencing non-global objects from markup. This came up in the Template Instantiation discussion too, for choosing template processors from markup. Once we solve that we should be able to tell a declarative shadow root which registry to use. Speculatively (and probably a poor choice of syntax, tbh) it could be something like this: <template is="declarative-shadow-root" registry="registry from ./registry.js">
...
</template> Where I think this is a separable concern though |
I think a common pattern that might emerge is sharing a registry across a whole package rather than per-module. Since in npm generally a package can only resolve a dependency to a single version, it'll be relatively safe to have a package-wide registry that handles the element subclassing automatically and is tolerant of re-registrations: registry.js export class AutoScopingCustomElementRegistry extends CustomElementRegistry {
constructor() {
this.bases = new Map();
}
define(name, constructor, options) {
if (this.bases.has(tagname)) {
const base = defined.get(tagname);
if (base !== constructor) {
throw new Error('Tried to redefine a tagname with a different class');
}
return; // already defined
}
super.define(name, class extends constructor {}, options);
}
}
export const registry = new AutoScopingCustomElementRegistry(); Now one module can define the element without making a trivial subclass: container-a.js import {registry} from './registry.js';
import {ChildElement) from './child-element.js';
registry.define('child-element', ChildElement); And another module too, but it's safe and shares the definition: container-b.js import {registry} from './registry.js';
import {ChildElement) from './child-element.js';
registry.define('child-element', ChildElement); It's possible this is useful enough that it should make it into the proposal. |
Not all APIs can be high-level, just like not all APIs can be low-level, but no API should be mid-level :). I truly believe that scope registry should be a low-level API, imperative, following the principles of EWM. It should be something that libraries, transpilers and framework authors can rely on. Most likely tools that can do the static analysis to either bundle things together, or create the corresponding registries. I don't think we should create an API for this and expect that citizen developers will use it on the daily basics. |
@caridy I don't think this proposal is at different of a level than the current CustomElementRegistry, and I don't think it would be only for tools. In fact a major reason for proposing this is to get closer to the scoping and workflow that pure-JS component solution enjoy. Consider the following React-ish example: import {ChildComponent} from './child-component.js';
export class ParentComponent extends Component {
render() {
return <ChildComponent>Hello</ChildComponent>;
}
} This has no problem with several components being named ChildComponent, supports renaming, and multiple versions in the same program. I think we can get very close to this with custom elements (this example using LitElement for conciseness, it just creates a shadow root automatically): import {ChildElement} from './child-element.js';
import {registry} from './registry.js';
registry.define('child-element', ChildElement);
export class ParentElement extends LitElement {
render() {
return html`<child-element>Hello</child-element>;
}
} This has no problem with several components being named child-element, supports renaming, and multiple versions in the same program, with only a slightly addition in LoC for making sure the element is registered. I see this as very hand-writable. |
In the example above (using LitElement), how does the |
In this example I'm showing the shared registry per package pattern I described above. I did forget to give the element the registry though. We need to add: export class ParentElement extends LitElement {
static get registry { return registry; }
} or: ParentElement.registry = registry; And have |
And then it'd be possible for SkateJS, StencilJS, PolymerJS, etc, to abstract away the boilerplate. :) |
@justinfagnani the point I was trying to make is that providing a very low level API for the registry allows to implement something like what you have described, and many other cases (like those that we have discussed in our meeting last week), library authors will create abstractions on top of that like the one you just described in Lit, and I believe that will be the primary way devs will consume this API, via abstraction. In your example above, you're adding the sugar layer via a) the import for the local registry and b) the static registry reference. And that is totally fine! What is not fine is to force framework, tool and library authors to have to do gymnastics to accomplish some scoping mechanism, and that's why I'm favoring a very low level API here. |
As far as I can tell, no one has yet explained how this will work: class MyElement extends HTMLElement {}
customRegistry.define('my-element', MyElement);
new MyElement(); Does this?
If the answer is the latter, meaning it is allowed, what happens when you then do: class MyElement extends HTMLElement {}
customRegistry.define('my-element', MyElement);
let el = new MyElement();
document.body.appendChild(el); Note that this is appending to the document body, which is not part of the |
@matthewp those are very good questions that need concrete answers. The second example could be simplified to just asking what happen when you insert an already upgraded element into a different shadow or global? IMO, since the shadow dom is not really a security mechanism, it will work just fine. Meaning that the scoped registry is about facilitating the upgrading process rather than a security boundary. Update: Thinking more about this, I believe the registry (custom or not) is just a mechanism to determine how to upgrade the elements, and not about where the element is used or not. |
@matthewp While this proposal removes the 1-1 relationship between a tagname and a constructor, it preserves a 1-1 relationship between a constructor and a registration, so for any given constructor call we know what tagname to create, and what registry to associate with the instance. This doesn't require putting constructors into a global set. In other words: class MyElement extends HTMLElement {}
customRegistry.define('my-element', MyElement);
const el = new MyElement(); would just work. And further: el.innerHTML = '<my-element></my-element>'; would also create a MyElement instance. For the second question: once upgraded, an element is never downgraded or re-upgraded. Creating an element in one scope and moving it to another should neither change it's prototype, nor the scope associated with the element. This could conceivably lead to some weird situations where after moving elements around, two elements in the same container produce different results (different prototypes) when setting their |
Summary of the discussion in Tokyo: Registry Inheritance & Scope LookupThere were some suggestions (with possibly mild agreement?) to make registry inheritance and scope lookup dynamic based on tree location. = That is, the CustomElementRegistry constructor would no longer take a parent argument, but look up a parent via the tree. This ensures that the structure of the registry tree agrees with the structure of the DOM tree. Likewise, looking up the registry to use for element-creation operations like The performance concerns I had seem to not be a concern for implementers, who say they can optimize this. Constructors & RegistrationsThere were few questions about how constructors would they behave. Would they only work if registered in the global registry? Could a constructor be registered with multiple registries, or would it requires trivial subclasses be registered in each? There was a desire to match iframe behavior, since it defines another registry scope already, so match what happens if you register a constructor in a frame then send the constructor to another frame. Some discussion also about how this relates to being able to lookup a tagname by constructor. If you allow a constructor to be registered multiple times, it doesn't have a single tag name. The v0 Element Creation APIsThere was a suggestion to put scoped element creation APIs on CustomElementRegistry, not ShadowRoot. Lazy RegistrationThis was talked about briefly for the use case of supporting a potentially very, very large number of tag names, by being notified the first time a tag name is used allowing the registry an opportunity to fetch the definition. This feature seems separable from scopes. |
@LarsDenBakker I sent a PR to @justinfagnani few weeks ago (right after the meeting) with the updates: I'm waiting for him at this point to look at it, also waiting for him to create the repo for the proposal, so we can start organizing this better now that we have some tentative consensus. I've few cycles to work on this, and to work on the spec as well, we just need to get rolling. |
Sorry Carridy, I didn't get a notification for the PR. Looking now. As for a repo, I haven't seen other proposals in this area get their own repo. Is there precedence or a template for that? |
A repo is easier IMO, e.g.: https://github.com/mfreed7/declarative-shadow-dom I'm fine either way! just let me know what works better. |
<div></div>
<parent-is-element-definition></parent-is-element-definition> div is the prevElementSibling of parent-is-element-definition <div id="instance1"></div>
<parent-is-element-definition></parent-is-element-definition>
<div id="instance2"></div>
<parent-is-element-definition></parent-is-element-definition>
<div></div>
<parent-is-element-definition></parent-is-element-definition>
<custom-name-one></custom-name-one>
<parent-is-element-definition></parent-is-element-definition> in that scenario i demonstrate the usage of a customElement that does fire a connectedCallback but apply the definition to the element before it |
@justinfagnani considering the precedence and also using it as an example, I believe a new repo could be useful. I'd like to offer my help - along with @caridy - to support this moving forward. I understand I'm a new comer here, but one of the advantages I estimate is that a new repo would find a better place to prepare everything specific. Even more after a good part of the web components migrated to other specs. WDYT? I'm looking forward to be of any help here! |
off topic:
For that problem, what I do is my libraries export only classes, then I let the consumer run import {TheClass} from ''the-library"
customElement.define('any-name-the-user-wants', TheClass)
// alternative API provided by my lib:
TheClass.define('any-name') // defined <any-name> elements. This way the end user has control on the application side instead of the library dictating the name. Lastly, all of my classes come with default names, that the user can opt into: import {TheClass} from ''the-library"
TheClass.define() // this registers the element with a default name, f.e. <the-class>
// alternatively register all classes in the whole lib with their default names:
import {useDefaultNames} from ''the-library"
useDefaultNames() This leaves applications with control. If they have a collision, the specific application can be modified to specify a different name.
As @frank-dspeed said, and as your security team should be saying, you should run entirely separate apps inside iframes. That's how you get security. Plus, an added benefit of this is that it would reduce custom element naming collisions because each iframe has its own registry. But please, lets not create off-topic conversations, because it makes it more difficult and tedious for spec authors to collaborate on the issue. Your issues are related, but not directly on topic. You can open a new help topic after first asking on StackOverflow and not getting any answers in a reasonable amount of time. As you may be able to tell, the collaborators are skipping the off-topic comments and attempting to work on the proposal. Moderators, if you can please mark this (and a couple previous replies) as off-topic, it'll prevent them from showing up in Google search results. |
@leobalter glad to hear the offer. I'll create a new repo today. |
@leobalter @caridy I created the repo here, just copying the initial text from the PR https://github.com/justinfagnani/scoped-custom-elements I'll make a PR to this to address the outstanding feedback. |
That's great, @justinfagnani! Thanks! |
Please, no. We already have this, HTML, and DOM repositories, and various issues and discussion are scattered across all those repositories' issue trackers and PRs. The last thing we want is adding even more repositories and issues and PRs to follow the discussion. |
One thing that's unclear from https://github.com/justinfagnani/scoped-custom-elements is that in which tree(s) existing unknown custom elements are upgraded in There is another subtle but important aspect. When a shadow root is created without an explicit registry, it must use document's registry. But this is the owner document of the element, not of the global object to which the element's prototype comes from. This is an important point. Because it would mean that if you adopt a custom element C_1 from a document D_A (e.g. template document) to another document D_B, then any nested shadow roots S_N in that custom element C1's shadow roots S_1 would default to the other document D_B's registry, not the original document D_A's. |
I believe each registry ( FWIW, |
I'm not sure I follow what you're saying. Multiple |
@rniwa can you put together some kind of example to showcase the issue? I'm having a hard time understanding the problem. |
const registry = new CustomElementRegistry;
const d1 = document.createElement('div');
d1.attachShadow({mode: 'closed', registry}).innerHTML = '<some-element id="d1s1"></some-element><some-element id="d1s2">';
const d2 = document.createElement('div');
d2.attachShadow({mode: 'closed', registry}).innerHTML = '<some-element id="d2s1">';
const d3 = document.createElement('div');
d3.attachShadow({mode: 'closed', registry}).innerHTML = '<some-element id="d3s1">';
const iframe = document.createElement('iframe');
document.body.append(d2, d1, iframe);
iframe.contentDocument.body.append(d3);
class SomeElement extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'closed'}).innerHTML = '<other-element></other-element>';
}
}
registry.define('some-element', SomeElement);
customElements.define('other-element', class OtherElement extends HTMLElement { }); Now, should d1s1, d1s2, d2s1, and d3s1 be upgraded? If so, in what order? Should other-element in d1s1, d1s2, d2s1, and d3s1's shadow trees be upgraded if so, in what order? |
Ok, this is great @rniwa, that clarifies a lot. My intution here is as follow:
with
Updated: While I believe your concrete question is about |
I don't think this is right. If it automatically "inherited" parent shadow tree's registry, then this raises a new question. What happens when SomeElement is instantiated outside of a shadow tree then inserted into another shadow tree with a scoped registry. Note that this is precisely what happens in synchronous element construction case (e.g. by using In other words, is the shadow tree's custom element registry determined at the time it's attached or is it dynamically determined by the tree structure. In order to have the semantics you described and not have an inconsistency between upgrade and synchronous construction case, we need to do the dynamic determination. But this poses yet another issue about temporarily detaching an element from a shadow tree so it's not great either. All in all, there is a lot of open questions here. |
i am not sure but i want to say something as i am deep into this stuff since some years. Out of my View There should be no such customRegistry needed all that the current reg does is calling some hooks. we can archive that with custom conditions and mutation observer in round about 10 short lines of code. So if one has the need for handling elements with a custom lifecycle Mutation Observer is the way to go it supports all that. Some none tested code examples out of my head showing all 4 hooks const attributesObserver = new MutationObserver(function(mutations, observer) {
mutations.forEach(function(mutation) {
if (mutation.type == "attributes") {
attributeChangedCallback.apply(mutation.target,[mutation.attributeName, mutation.oldValue mutation.target.getAttribute(mutation.attributeName)])
}
});
});
const childListObserver = new MutationObserver(function(mutations, observer) {
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(connectedCallback.apply)
mutation.removededNodes.forEach(disconnectedCallback.apply)
}
});
});
attributesObserver.observe(el, {
attributes: true, //configure it to listen to attribute changes
attributeOldValue: true,
attributeFilter: ['hidden', 'contenteditable', 'data-par'] // individual listen to attributes.
});
childListObserver.observe(el.parent, { childList: true, subtree: true }); |
I think you're right, let me update my comment above to reflect that
I was under the impression that we have some previous agreements about these cases: when an element is upgraded inside a shadow root, the lookup will occur at that point, while
In the explainer, it is listed as dynamically determined by the tree structure. This opens the door for replacing the registry at any given time, as a possibility, or just replacing the registry when adopted by another document, etc. About the temporarily detaching an element issue that you mentioned above, can you provide more information? Maybe another example? The way I see it, if an element is upgraded already (dynamically or via sync construction), and that element is temporarily detaching (while moving it around), it should not have any side effects on any element from its shadow root that was already upgraded. |
Since #488 is closed, I thought I'd open up a new issue to discuss a relatively specific proposal I have for Scoped Custom Element Registries.
Scoped Custom Element Definitions
Overview
Scoped Custom Element definitions is an oft-requested feature of Web Components. The global registry is a possible source of name collisions that may arise from coincidence, or from an app trying to define multiple versions of the same element, or from more advanced scenarios like registering mocks during tests, or a component explicitly replacing an element definition for its scope.
Since the key DOM creation APIs are global, scoping definitions is tricky because we'd need a machanis to determind which scope to use. But if we offer scoped versions of these APIs the problem is tractable. This requires that DOM creation code is upgraded to use the new scoped APIs, something that hopefully could be done in template libraries and frameworks.
This proposal adds the ability to construct
CustomElementRegistry
s and chain them in order to inherit custom element definitions. It usesShadowRoot
as a scope for definitions.ShadowRoot
can be associated with aCustomElementRegistry
when created and gains element creation methods, likecreateElement
. When new elements are created within aShadowRoot
, thatShadowRoot
's registry is used to Custom Element upgrades.API Changes
CustomElementRegistry
CustomElementRegistry(parent?: CustomElementRegistry)
CustomElementRegistry
is constructable, and able to inherit from a parent registry.New definitions added to a registry are not visible to the parent, and mask any registrations with the same name defined in the parent so that definitions can be overridden.
CustomElementRegistry.prototype.get(name: string)
get()
now returns the closest constructor defined for a tag name in a chain of registries.CustomElementRegistry.prototype.getRegistry(name: string)
Returns the closest registry in which a tag name is defined.
ShadowRoot
ShadowRoot
s are already the scoping boundary for DOM and CSS, so it's natural to be the scope for custom elements.ShadowRoot
needs aCustomElementRegistry
and the DOM creation APIs that current exist on document.customElements: CustomElementRegistry
The
CustomElementRegistry
theShadowRoot
uses, set onattachShadowRoot()
.createElement()
,createElementNS()
These methods create new elements using the
CustomElementRegistry
of theShadowRoot
.importNode()
Imports a node into the document that owns the
ShadowRoot
, using theCustomElementRegistry
of theShadowRoot
.This enables cloning a template into multiple scopes to use different custom element definitions.
Element
New properties:
Element.prototype.scope: Document | ShadowRoot
Elements have DOM creation APIs, like
innerHTML
, so they need a reference to their scope. Elements expose this with ascope
property. One difference between this andgetRootNode()
is that the scope for an element can never change.Element.prototype.attachShadow(init: ShadowRootInit)
ShadowRootInit
adds a new property,customElements
, in its options argument which is aCustomElementRegistry
.With a scope, DOM creation APIs like
innerHTML
andinsertAdjacentHTML
will use the element'sscope
's registry to construct new custom elements. Appending or inserting an existing element doesn't use the scope, nor does it change the scope of the appended element. Scopes are completely defined when an element is created.Example
Questions
What happens to existing upgraded elements when an overriding definition is added to a child registry?
The simplest answer is that elements are only ever upgraded once, and adding a new definition that's visible in an element's scope will not cause a re-upgrade or prototype change.
Should classes only be allow to be defined once, across all registries?
This would preserve the 1-1 relationship between a class and a tag name and the ability to do
new MyElement()
even if a class is not registered in the global registry.It's easy to define a trivial subclass if there's a need to register the same class in different registries or with different names.
Should registries inherit down the tree-of-trees by default, or only via the parent chain of
CustomElementRegistry
?Inheriting down the DOM tree leads to dynamic-like scoping where definitions can change depending on your position in the tree. Restricting to inheriting in
CustomElementRegistry
means there's a fixed lookup path.Should the registry of a
ShadowRoot
be final?Is
Element.prototype.scope
neccessary?It requires all elements to remember where they were created, possibly increasing their memory footprint. Scopes could be dynamically looked up during new DOM creation via the
getRootNode()
process instead, but this might slow down operations likeinnerHTML
.How does this interact with the Template Instantiation proposal?
With Template Instantiation
document.importNode()
isn't used to create template instances, butHTMLTemplateElement.prototype.createInstance()
. How will that know which scope to use? Should it take a registry orShadowRoot
?/cc @domenic @rniwa @hayatoito @TakayoshiKochi
The text was updated successfully, but these errors were encountered: