-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Revamped Scoped Custom Element Registries #10854
Comments
So to this.shadowRoot.customElements.createElement('my-el'); Is that correct? |
Will the global function cloneInScope(src: DocumentFragment, scope: Document | ShadowRoot | Element = document) {
const registry = scope.customElements ?? globalThis.customElements;
return registry.cloneSubtree(src);
} Assuming the above, then at first glance, this proposal looks like it will enable all my scenarios. |
@EisenbergEffect : Yes, |
Yes although a more convenient way is to use whatever node you already have in the shadow tree and do: node.customElements.createElement('my-el'); |
Right so from “inside” a custom element you could either do Additionally, I think the addition of allowing a registry for a node is a good addition 👍 |
Why happens in this scenario? <outer-element>
<template shadowrootmode="open">
<inner-element></inner-element>
</template>
<outer-element>
<inner-element></inner-element> Assuming that there are different definitions for |
@matthewp : in that scenario, all the elements will use the global registry since there is nothing on |
@rniwa Thanks, that was my suspicion. That seems like a show-stopper to me. Can we add something to |
In the proposal @annevk made above, there is |
Thanks very much for working on this @rniwa and @annevk! I think this proposal is an improvement over the original. I have a few questions and refinement suggestions. initializing a registryIt seems problematic to expose this only via <div id="host">
<template shadowrootmode="open" shadowrootcustomelements="">
<x-foo></x-foo>
</template>
</div> Putting an API to initialize a registry on I also think it would be great to be able to create an imperative shadowRoot with a blank Might this be workable? const shadowRoot = element.attachShadow({mode: 'closed', customElements: null});
shadowRoot.innerHTML = `
<x-foo> <x-bar></x-bar>...</x-foo>
<x-foo> <x-bar></x-bar>... </x-foo>
`;
const xFoo1 = shadowRoot.firstElementChild;
const xFoo2 = shadowRoot.lastElementChild;
xFoo1.customElements = registryA; // upgrades XFoo1 and its subtree in registryA?
shadowRoot.customElements = registryB; // upgrades XFoo2 in registryB?
//
xFoo1.customElements = registryB // throws. cloning
console.assert(element.customElements == registryA); // ok
const clone = element.cloneNode(true);
console.assert(clone.constructor == registryA.get(clone.localName)) // ok?
|
Thanks for making this revision @annevk and @rniwa. I'm very glad that it seems like we can just have elements remember their registry and not have to always defer to shadow roots! A few questions / concerns: Element creationI think that in order to get frameworks and rendering libraries to support for scoped registries we have to make it extremely easy and performance-neutral for them to add. The way I had proposed this was to add Because ShadowRoot's optionally had an associated CustomElementsRegistry and fell back to global creation when they didn't have one, a library could always use the shadow root as the creation object, and fall back to the document when not rendering into a shadow root. This simplifies element creation a lot - there's little code or perf overhead to supporting scoped registries. For example, In lit-html, we pass either // Use the global scope always. (document is also the default)
render(html`<x-foo></x-foo>`, {creationScope: document});
// In a web component, use registry of the shadow root, which may or may not have a scoped registry
render(html`<x-foo></x-foo>`, {creationScope: this.shadowRoot}); On the library side, support for scopes is as simple as: const fragment = (options?.creationScope ?? document).importNode(template.content, true); I worry that an API like I think it'd be an easier lift if instead we made it possible to use a Document or ShadowRoot in more cases as a scope object. They have other useful common APIs like This wouldn't preclude element creation APIs from also existing on CustomElementsRegistry. Non-shadow DOM usage and SSRI think that like <body>
<x-feature-1>
<x-foo></x-foo>
</x-feature-1>
<x-feature-2>
<x-foo></x-foo>
</x-feature-2>
</body> Where |
The way we are envisioning this API will be used is that we'd use CustomElementRegistry as scoping object instead of ShadowRoot. It's more natural that way since you'd often construct a tree without necessarily having access to the future root node. You can easily fallback to document like this: It's possible to add convenience functions on ShadowRoot as well but it did seem like something we can wait for the community feedback. |
It's possible to extend this API to support an element with null registry in a document tree as a thing by introducing a new content attribute for the parser to consume but I don't think we should include that in the initial version unless we can find very important use cases that require that. |
Is that a common scenario? I can't think of a situation in which author uses a declarative DOM in conjunction with a scoped custom element without using a custom element on the shadow host. What are concrete use cases? |
We had considered that option but concluded that a setter which allows setting once then starts throwing is an exotic behavior we want to avoid. We also had hopes to make it so that elements are never exposed to scripts until its registry is initialized. However, now we realize this is not possible since end user could interact with such an element and trigger a composed event before scripts had a chance to define its registry (or else it sort of defeats the whole point of SSR). So given that, we can revisit this alternative design. |
The primary way cloneSubtree differs from importNode is that it does deep cloning by default as Mozilla had advocated in the past (since that's what you want in most cases anyway) when we were standardizing cloneNode's default argument to be optional. We thought using the same method name would be confusing given that distinction. |
We've seen a lot of interest in using scoped registries for micro-frontends (MFE) where a subtree might be managed in a framework that either doesn't use custom elements and/or doesn't want Shadow DOM. The general problem with these MFE use cases is that tend to be very over-constrained so the platform must be expressive and flexible to handle them. We can definitely try to get more feedback on these issues. Consider this scenario... <div id="svelte-app">
<template shadowrootmode="closed" shadowrootcustomelements>
My svelte MFE
<design-system-button>version 1.2.3 so must be that registry</design-system-buttton>
</template>
</div>
<div id="vue-app">
<template shadowrootmode="closed" shadowrootcustomelements>
My vue MFE
<design-system-button>version 1.1.7 so must be that registry</design-system-buttton>
</template>
</div>
<div id="react-app" customelements="">
My react MFE (needs global styling!)
<design-system-button>version 1.3.8 so must be that registry</design-system-buttton>
</div> |
One reason I (mildy) prefer at least the option of using a ShadowRoot as the scoping object is that it has other scope-related APIs, like Of course, as you point out, both Document and ShadowRoot would have I know similar arguments were made about the Another issue for me is (root.customElements?.cloneSubtree?.(template.content) ?? document.importNode(template.content, true) vs (root.importNode ?? document.importNode)(template.content, true) It might not seem like much, but we've seen pushback over similar things. I also have a question about the value
One nice thing about |
I can see MFE may not want to use shadow DOM. But the combination of waiting to use shadow DOM and scoped custom element registry but not custom elements for the host seems like odd combination to me. What are examples of frameworks / libraries / websites that do this? |
To us, it seemed weird that
That might be an argument for making
Over time (with any polyfill), the former will simplify to just
It points to the global registry.
That is tautologically true of |
It seems really odd to me to have |
here’s the MFE use case that is of interest to me. as usual it’s a design system use case. let’s say i have a design system written in web components. so all my buttons, modals, tooltips, etc are custom elements but the app i’m writing is a react app that consumes those elements. and my app is an MFE remote app that gets loaded async on the same page as another MFE remote app also in react AND the “host” app which is the parent of all the MFE remotes. my app is not the whole page shown to users, but just a part of it. and my app is rendered by react (a shared dependency from my app contains v1.0.0 of the design system button, x-button. and the host app has v0.0.2 of x-button and another MFE remote app has v2.0.0 of x-button all at the same time. scoping is needed so we go to set it up so that my MFE app version of the design system components can’t conflict with the host app or other MFEs remote apps that might be rendered into the same page as my MFE remote. under the existing proposal, i’d have to:
it would be easier if registries and shadow roots were disconnected because i wouldn’t have render my MFE app in shadow root. if there was a way to programmatically just “apply a registry to some div perpetually” then an MFE setup could just create the registry and the react render root separately with js, then link them together without having to involve react internals at all. if i could do something like: const registry = new Registry();
//add els to registry
registry.define(‘x-button’);
const root = React.createRoot(‘div’);
// tell the root that all WCs in it should use the registry first, global as a fallback
root.attachRegistry(registry);
root.render(<MyApp/>); and not involve react at all that would be amazing for MFEs |
I agree with @michaelwarren1106 like I tried to make clear in discord I would love to have a similar way to how forms work currently if you wrap a form around input elements they register to that unless you set the form attribute on the input to something else. You can also apply this attribute form I think to an input outside the form tag. <!-- this registereds all to the form / could this method also work for custom elements? -->
<form id="myForm" action="/submit" method="post">
<button type="submit">Submit</button>
<input type="password" name="password" placeholder="password">
</form>
<input type="text" name="username" form="myForm" placeholder="Username">
<input type="text" name="email" form="myForm" placeholder="Email"> |
https://bugs.webkit.org/show_bug.cgi?id=286870 Reviewed by Chris Dumez. This PR implements a number of API changes we proposed in whatwg/html#10854. Since the new API's behavior is sufficiently different from the old proposal, this PR opts to write a new set of tests instead of retrofitting the old tests to match the new behavior. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Construct.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Construct.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-define.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-define.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-initialize.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-initialize.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-upgrade.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/CustomElementRegistry-upgrade.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Document-createElement.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Document-createElement.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Document-importNode.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Document-importNode.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-customElements-exceptions.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-customElements-exceptions.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-customElements.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-customElements.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-innerHTML.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/Element-innerHTML.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/ShadowRoot-init-customElements.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/ShadowRoot-init-customElements.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/ShadowRoot-innerHTML.tentative-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry/ShadowRoot-innerHTML.tentative.html: Added. * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/ShadowRoot-createElement.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/ShadowRoot-importNode.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/ShadowRoot-init-registry.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/ShadowRoot-innerHTML-upgrade.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/ShadowRoot-innerHTML.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/constructor-reentry-with-different-definition.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/scoped-registry-define-upgrade-criteria.tentative-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/custom-elements/scoped-registry/scoped-registry-define-upgrade-order.tentative-expected.txt: * Source/WebCore/CMakeLists.txt: * Source/WebCore/DerivedSources-input.xcfilelist: * Source/WebCore/DerivedSources-output.xcfilelist: * Source/WebCore/DerivedSources.make: * Source/WebCore/Headers.cmake: * Source/WebCore/Sources.txt: * Source/WebCore/WebCore.xcodeproj/project.pbxproj: * Source/WebCore/dom/Attr.cpp: (WebCore::Attr::cloneNodeInternal): * Source/WebCore/dom/Attr.h: * Source/WebCore/dom/CDATASection.cpp: (WebCore::CDATASection::cloneNodeInternal): * Source/WebCore/dom/CDATASection.h: * Source/WebCore/dom/Comment.cpp: (WebCore::Comment::cloneNodeInternal): * Source/WebCore/dom/Comment.h: * Source/WebCore/dom/ContainerNode.cpp: (WebCore::ContainerNode::cloneChildNodes): * Source/WebCore/dom/ContainerNode.h: * Source/WebCore/dom/CustomElementReactionQueue.cpp: (WebCore::CustomElementReactionQueue::tryToUpgradeElement): * Source/WebCore/dom/CustomElementRegistry.cpp: (WebCore::upgradeElementsInShadowIncludingDescendants): (WebCore::CustomElementRegistry::upgrade): (WebCore::CustomElementRegistry::initialize): (WebCore::CustomElementRegistry::addToScopedCustomElementRegistryMap): * Source/WebCore/dom/CustomElementRegistry.h: (WebCore::CustomElementRegistry::registryForElement): (WebCore::CustomElementRegistry::registryForNodeOrTreeScope): * Source/WebCore/dom/CustomElementRegistry.idl: * Source/WebCore/dom/Document.cpp: (WebCore::createUpgradeCandidateElement): (WebCore::createHTMLElementWithNameValidation): (WebCore::Document::createElementForBindings): (WebCore::Document::importNode): (WebCore::createFallbackHTMLElement): (WebCore::Document::createElement): (WebCore::Document::createElementNS): (WebCore::Document::cloneNodeInternal): (WebCore::TreeScope::createElementForBindings): Deleted. (WebCore::TreeScope::createElement): Deleted. (WebCore::TreeScope::createElementNS): Deleted. * Source/WebCore/dom/Document.h: (WebCore::Document::setSawElementsInKnownNamespaces): Deleted. * Source/WebCore/dom/Document.idl: * Source/WebCore/dom/DocumentFragment.cpp: (WebCore::DocumentFragment::cloneNodeInternal): * Source/WebCore/dom/DocumentFragment.h: * Source/WebCore/dom/DocumentType.cpp: (WebCore::DocumentType::cloneNodeInternal): * Source/WebCore/dom/DocumentType.h: * Source/WebCore/dom/Element.cpp: (WebCore::Element::cloneNodeInternal): (WebCore::Element::cloneShadowTreeIfPossible): (WebCore::Element::cloneElementWithChildren): (WebCore::Element::cloneElementWithoutChildren): (WebCore::Element::cloneElementWithoutAttributesAndChildren): (WebCore::Element::insertedIntoAncestor): (WebCore::Element::removedFromAncestor): (WebCore::Element::customElementRegistry const): * Source/WebCore/dom/Element.h: * Source/WebCore/dom/Element.idl: * Source/WebCore/dom/ElementCreationOptions.h: Copied from Source/WebCore/dom/ShadowRootInit.h. * Source/WebCore/dom/ElementCreationOptions.idl: Copied from Source/WebCore/dom/ShadowRootInit.idl. * Source/WebCore/dom/ImportNodeOptions.h: Copied from Source/WebCore/dom/ShadowRootInit.h. * Source/WebCore/dom/ImportNodeOptions.idl: Copied from Source/WebCore/dom/ShadowRootInit.idl. * Source/WebCore/dom/Node.cpp: (WebCore::Node::cloneNode): * Source/WebCore/dom/Node.h: (WebCore::Node::usesNullCustomElementRegistry const): (WebCore::Node::setUsesNullCustomElementRegistry const): (WebCore::Node::clearUsesNullCustomElementRegistry const): * Source/WebCore/dom/ProcessingInstruction.cpp: (WebCore::ProcessingInstruction::cloneNodeInternal): * Source/WebCore/dom/ProcessingInstruction.h: * Source/WebCore/dom/ShadowRoot.cpp: (WebCore::ShadowRoot::insertedIntoAncestor): (WebCore::ShadowRoot::removedFromAncestor): (WebCore::ShadowRoot::registryForBindings const): (WebCore::ShadowRoot::cloneNodeInternal): * Source/WebCore/dom/ShadowRoot.h: * Source/WebCore/dom/ShadowRoot.idl: * Source/WebCore/dom/ShadowRootInit.h: * Source/WebCore/dom/ShadowRootInit.idl: * Source/WebCore/dom/Text.cpp: (WebCore::Text::cloneNodeInternal): * Source/WebCore/dom/Text.h: * Source/WebCore/dom/TreeScope.cpp: (WebCore::TreeScope::setCustomElementRegistry): (WebCore::TreeScope::importNode): Deleted. * Source/WebCore/dom/TreeScope.h: (WebCore::TreeScope::customElementRegistry const): * Source/WebCore/editing/ApplyStyleCommand.cpp: (WebCore::ApplyStyleCommand::pushDownInlineStyleAroundNode): (WebCore::ApplyStyleCommand::applyInlineStyleChange): * Source/WebCore/editing/BreakBlockquoteCommand.cpp: (WebCore::BreakBlockquoteCommand::doApply): * Source/WebCore/editing/InsertParagraphSeparatorCommand.cpp: (WebCore::InsertParagraphSeparatorCommand::cloneHierarchyUnderNewBlock): (WebCore::InsertParagraphSeparatorCommand::doApply): * Source/WebCore/editing/MarkupAccumulator.cpp: (WebCore::MarkupAccumulator::startAppendingNode): * Source/WebCore/editing/ModifySelectionListLevel.cpp: (WebCore::IncreaseSelectionListLevelCommand::doApply): * Source/WebCore/editing/SplitElementCommand.cpp: (WebCore::SplitElementCommand::doApply): * Source/WebCore/editing/TextManipulationController.cpp: (WebCore::TextManipulationController::updateInsertions): * Source/WebCore/editing/markup.cpp: (WebCore::createFragmentFromText): * Source/WebCore/html/AttachmentAssociatedElement.cpp: (WebCore::AttachmentAssociatedElement::cloneAttachmentAssociatedElementWithoutAttributesAndChildren): * Source/WebCore/html/AttachmentAssociatedElement.h: * Source/WebCore/html/HTMLAttributeNames.in: * Source/WebCore/html/HTMLImageElement.cpp: (WebCore::HTMLImageElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/HTMLImageElement.h: * Source/WebCore/html/HTMLInputElement.cpp: (WebCore::HTMLInputElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/HTMLInputElement.h: * Source/WebCore/html/HTMLScriptElement.cpp: (WebCore::HTMLScriptElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/HTMLScriptElement.h: * Source/WebCore/html/HTMLSourceElement.cpp: (WebCore::HTMLSourceElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/HTMLSourceElement.h: * Source/WebCore/html/HTMLTemplateElement.cpp: (WebCore::HTMLTemplateElement::cloneNodeInternal): (WebCore::HTMLTemplateElement::attachAsDeclarativeShadowRootIfNeeded): Deleted used code. * Source/WebCore/html/HTMLTemplateElement.h: * Source/WebCore/html/HTMLTemplateElement.idl: * Source/WebCore/html/parser/HTMLConstructionSite.cpp: (WebCore::HTMLConstructionSite::insertHTMLTemplateElement): (WebCore::HTMLConstructionSite::createElement): (WebCore::HTMLConstructionSite::createHTMLElementOrFindCustomElementInterface): * Source/WebCore/html/shadow/SliderThumbElement.cpp: (WebCore::SliderThumbElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/shadow/SliderThumbElement.h: * Source/WebCore/html/track/TextTrackCue.cpp: (WebCore::TextTrackCue::create): (WebCore::TextTrackCue::getCueAsHTML): (WebCore::TextTrackCue::rebuildDisplayTree): * Source/WebCore/html/track/VTTCue.cpp: (WebCore::VTTCue::createCueRenderingTree): * Source/WebCore/html/track/WebVTTElement.cpp: (WebCore::WebVTTElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/html/track/WebVTTElement.h: * Source/WebCore/inspector/agents/InspectorDOMAgent.cpp: * Source/WebCore/page/LocalDOMWindow.cpp: (WebCore::LocalDOMWindow::ensureCustomElementRegistry): * Source/WebCore/svg/SVGScriptElement.cpp: (WebCore::SVGScriptElement::cloneElementWithoutAttributesAndChildren): * Source/WebCore/svg/SVGScriptElement.h: * Source/WebCore/svg/SVGUseElement.cpp: (WebCore::SVGUseElement::cloneTarget const): (WebCore::cloneDataAndChildren): * Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp: (WebCore::XMLDocumentParser::startElementNs): * Source/WebKitLegacy/mac/DOM/DOMDocument.mm: Canonical link: https://commits.webkit.org/290096@main
Can someone share the updated state of the API based on today's discussion? I wasn't able to make the meeting and I'd love to be able to update my libraries/frameworks based on the latest to make sure it's doable. Thanks in advance! |
I added a bunch of tests for the latest proposal in https://github.com/WebKit/WebKit/tree/main/LayoutTests/imported/w3c/web-platform-tests/custom-elements/revamped-scoped-registry |
Thank you @rniwa! This was tremendously helpful. Using the tests, I was able to update my framework code and confirm that these APIs will work in a pretty straight forward manner for me. I've implemented both server rendering with DSD and custom registry initialization as well as pure client-side shadow dom creation with custom registries. (Code is not open source yet. Working on a path to that eventually.) |
DOM PR: whatwg/dom#1341. Tests: ... Closes #10854.
I have updated OP with the latest IDL sketch. If you want to know the actual semantics, please read the PRs: Feedback is welcome in this issue or a sub-issue (you can file one through the button at the bottom of #10854 (comment)). You can also give feedback in the DOM issue (or create a sub-issue thereof): whatwg/dom#1339. Updated tests are at web-platform-tests/wpt#50790 though are not yet merged due to a linting issue. I've asked on the WPT Matrix how to best address that. (The tests and WebKit don't fully account for the latest discussion around |
The only thing that seems weird to me here is the const imported = document.importNode(element)
console.assert(imported.childNodes.length, 0);
const importedScoped = document.importNode(element, {customElements});
// can fail
console.assert(importedScoped.childNodes.length, 0); |
This is what we came up with in the last meeting on this topic. I don't think adding a separate method is okay, given the precedent we established with |
I think the "default" has to change because right now an empty object as the second parameter is interpreted as truthy, therefore So the options objects opts you into deep, and |
Unless I'm mistaken, this isn't how el.addEventListener(..., true) // captures
el.addEventListener(..., {capture: true}) // captures
el.addEventListener(..., {}) // does *not* capture |
But |
Maybe, but was adding the options bag to It is true that Was |
For |
I think the one confusing case is if you had an existing self-only import, that could be passed a node with children, and you need to update the call to pass a custom element registry. You might not immediately realize that you also need the I suspect that's a very, very small number of cases, and hope that any confusion would be quickly sorted. |
@matthewp it seems your question went unanswered. This new spec still has shadow root registries, which covers your case right? If not, can you explain what you see you cannot do with the new API? |
@trusktr I want to use scoped registers without creating custom elements, on any element that has a shadowRoot (like a div). I can't tell from the tests if that's possible now or not. |
I'm a bit confused here. Scoped custom element registry will necessarily work with custom elements? Are you asking whether you can use a scoped custom element registry on a builtin element with shadow tree? The new proposal does allow you to do that by specifying the registry in |
@trusktr @matthewp that feedback was addressed back in December: #10854 (comment). The proposal no longer uses |
Perfect, thank you. |
DOM PR: whatwg/dom#1341. Tests: ... Closes #10854.
https://github.com/WICG/webcomponents/blob/gh-pages/proposals/Scoped-Custom-Element-Registries.md is a good proposal, but it ties the functionality too much to shadow roots. This is Ryosuke and I's proposed improvement attempting to account for feedback given in various Web Components issues on this topic: https://github.com/WICG/webcomponents/issues?q=is%3Aissue+label%3A%22scoped+custom+element+registry%22.
First, the IDL, illustrating the new members:
Here’s a summary of how the proposal evolved:
CustomElementRegistry
still gains a constructor.ShadowRoot
still supports aCustomElementRegistry
, exposed through acustomElements
getter.shadowrootcustomelements
attribute, which is reflected as a string for forward compatibility.ElementInternals
gainsinitializeShadowRoot()
CustomElementRegistry
gainsinitialize()
so a declarative shadow root (or any element) can have itsCustomElementRegistry
set (when it’s null).attachShadow()
member is now calledcustomElements
for consistency.Element
should support an associatedCustomElementRegistry
, exposed through acustomElements
getter. This impacts elements created throughinnerHTML
and future such methods, such assetHTMLUnsafe()
. This will allow using non-globalCustomElementRegistry
outside of shadow roots.setHTMLUnsafe()
in the future could maybe also set its ownCustomElementRegistry
. Given the ergonomics of that it makes sense to expose it directly onElement
as well.document.createElement()
,document.createElementNS()
, anddocument.importNode()
are updated to account for registries.I’ll create specification PRs as well to allow for review of the processing model changes. We believe this resolves the remaining issues with the latest iteration of the initial proposal.
I'd like to briefly go over this in the December 19 WHATNOT meeting and will also be available then to answer any questions. Marking agenda+ therefore.
cc @rniwa @justinfagnani @whatwg/components
Minor issue tracker:
createElement()
we should attempt to reuse the existing one ondocument
(with a newcustomElements
member) as we're not quite ready to reinvent how to best do element-creation.initializeSubtree()
perform upgrades in the connected case? (If yes, it should probably also update the scoped document set.) (No.)initializeSubtree()
? (Also consider the names already exposed on this object.) Just initialize.importNode()
is better after all as we need a document anyway. So we should go with adocument.importNode(node, { subtree, customElements })
overload.The text was updated successfully, but these errors were encountered: