Skip to content
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

[Scoped registry] Clarify relationship with shadow roots #965

Open
wants to merge 2 commits into
base: gh-pages
Choose a base branch
from

Conversation

nolanlawson
Copy link

After reading through this proposal, I was a bit confused about the relationship between shadow roots and custom elements. It took me a moment to realize that custom elements' definitions are not defined by the shadow root attached to them, but instead to the shadow root that contains them.

This PR adds some clarifying notes that hopefully would help others reading this document. (Assuming that my interpretation is correct. 🙂)

After reading through this proposal, I was a bit confused about the relationship between shadow roots and custom elements. It took me a moment to realize that custom elements' definitions are not defined by the shadow root _attached_ to them, but instead to the shadow root that _contains_ them.

This PR adds some clarifying notes that hopefully would help others reading this document. (Assuming that my interpretation is correct. 🙂)
</body>
```

In the above example, `<light-element>` is scoped within the shadow root of its containing `<shadow-element>`, whereas `<shadow-element>` is defined at the global document level.
Copy link

@sashafirsov sashafirsov Aug 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we reflect that scope could be more flexible and tied not just to shadowRoot?

There is a scenario when light-element would have declarative custom element definition inside which would be logical to scope to the parent (or somehow named scope) instead whole page.

<body>
  <light-element>
    #light-root (registry=myCustomRegistry)
      <definition tag="custom-element">...</definition><!-- syntax is not clear as of now -->
      <custom-element>
        <div>Light DOM</div>
      </custom-element>
  </light-element>
</body>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this. Declarative custom element definitions do not exist yet, and there's no such thing as a light-root.

If <light-element> wants its own scope it'll have to programmatically create one and ensure that an elements it create use scoped instantiation APIs, which right now are only available on ShadowRoot, though we could conceivably also add them to CustomElementRegistry.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was under the impression that Declarative Shadow DOM was out-of-scope for this proposal... Although there is some reference to it here.

Copy link

@sashafirsov sashafirsov Aug 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declarative Shadow DOM has its sibling and evolution as Declarative Custom Element which could use shadow but also could live without, both in a baking now, not yet a proposal but already have POCs. Both could have a use for scoped registry as scoped by encapsulation as by namespace( a components library ).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declarative shadow DOM has nothing to do with declarative custom elements. They are unrelated conceptually, as declarative custom elements would not use declarative shadow DOM, and are at very, very different stages of proposal and implementation.

@@ -60,6 +60,8 @@ registry.define('other-element', OtherElement);

Definitions in this registry do not apply to the main document, and vice-versa. The registry must contain definitions for all elements used.

Note that, in the above example, `<other-element>` is defined in the scoped registry, not `<my-element>`. The registry applies to definitions _within_ the shadow root, not the element that the shadow root is attached to.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm finding this wording a bit unclear.... especially "<other-element> is defined in the scoped registry, not <my-element>" and "not the element that the shadow root is attached to."

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to tweak the language a bit. Maybe I'm only muddying things further, but the existence of <my-element> really confused me when I first read this, so I'm trying to call that out.

Arguably this example could just attach the shadow root to a div (or something), but that might be even more confusing since it isn't a common usage of shadow DOM.

@@ -119,6 +121,23 @@ As a result, it must limit constructors by default to only looking up registrati

This poses a limitation for authors trying to use the constructor to create new elements associated to scoped registries but not registered as global. More flexibility can be analyzed post MVP, for now, a user-land abstraction can help by keeping track of the constructor and its respective registry.

### Note on light DOM custom elements

Custom elements that use light DOM (i.e. that don't call `this.attachShadow()`) may be scoped, but they must be scoped within a shadow root. For example:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a bit confusing as there's no difference in defining elements in a scoped registry, regardless of whether they do or don't use shadow DOM. This seems to be blurring the language between what scope an element is defined in vs whether the element can have its own scope for its own definitions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this section to answer a question that may pop into people's heads (it certainly popped into mine), which is: "Wait, this proposal doesn't work for light-DOM-using web components?"

I'm trying to demonstrate that light-DOM-using components are perfectly compatible with this proposal, although maybe there's a better way to phrase this.

</body>
```

In the above example, `<light-element>` is scoped within the shadow root of its containing `<shadow-element>`, whereas `<shadow-element>` is defined at the global document level.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this. Declarative custom element definitions do not exist yet, and there's no such thing as a light-root.

If <light-element> wants its own scope it'll have to programmatically create one and ensure that an elements it create use scoped instantiation APIs, which right now are only available on ShadowRoot, though we could conceivably also add them to CustomElementRegistry.

@justinfagnani
Copy link
Contributor

@nolanlawson Sorry, I'm a little confused by your confusion and the statement "custom elements' definitions are not defined by the shadow root attached to them, but instead to the shadow root that contains them".

In this proposal ShadowRoots can be associated with a registry. When they are, elements created in that ShadowRoot via the scoped element creation APIs (shadowRoot.createElement(), etc) will use that registry instead of the global registry.

@nolanlawson
Copy link
Author

Thanks @justinfagnani yes, I think I get that subtlety now. My confusion stems from the fact that in this case:

const registry = new CustomElementRegistry()
customElements.define('my-element', class extends HTMLElement {
  constructor() {
    super()
    this.attachShadow({ mode: 'open', registry })
  }
})

... <my-element> is actually not the scoped definition. Instead, it's any other custom elements that are defined inside of <my-element>'s shadow root.

I could be wrong, but it seems to me that this could be a common confusion, because of the proximity of my-element to the registry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants