shoelace-style / shoelace

A collection of professionally designed, every day UI components built on Web standards. SHOELACE IS BECOMING WEB AWESOME 👇👇👇
https://webawesome.com
MIT License
12.66k stars 804 forks source link

Scoped Custom Elements and non-auto-defining imports #1375

Closed KonnorRogers closed 1 year ago

KonnorRogers commented 1 year ago

What issue are you having?

Sometimes I want to build a web component that uses shoelace internally in it's shadow dom. By adding ScopedCustomElementsMixin, we can enable UI authors to use shoelace internally in their components.

Describe the solution you'd like

Scoped Custom Elements to define Shoelace WC dependencies in the shadow dom, and non-auto-registering files to grab class definitions without needing to register the component (core piece of scoped elements)

Current thoughts

// Does not auto register
import SlAlert from "@shoelace-style/shoelace/dist/components/alert/alert.component.js"

// Auto registers
import SlAlert from "@shoelace-style/shoelace/dist/components/alert/alert.js"
claviska commented 1 year ago

Some questions, as I'm only a bit familiar with @open-wc/scoped-elements:

And some technical questions:

justinfagnani commented 1 year ago

One thing I would be careful about for the moment is that as the native proposal progresses we make sure that the polyfill will behave correctly when run against native implementations. I think we need to make the polyfill always enable itself even when the natively implementation is present so that differences in the native implementation don't break deployed sites. Once that's in place, it should be safe to use.

To get it to work you will have to use the ScopedRegistryMixin in all of your components that use other components. Another feature that you will need is for the ScopedRegistryMixin to fall back to the global registry if the scoped registry API isn't present.

thepassle commented 1 year ago
  • What problem(s) does this solve?

scoped-elements solves the issue of when you may need to support multiple versions of components on the same page. Like sl-button@1.0.0 and sl-button@2.0.0. This is usually a requirement that is common in large applications (because it allows teams to migrate gradually, instead of doing big bang migrations), or apps that use microfrontend architecture

  • Does this benefit all users or only Lit users?

@open-wc/scoped-elements is made for usage with Lit (because it relies on the createRenderRoot method). A component that uses scoped elements benefits everyone though; its still just an implementation detail of your element. Its just about preventing multiple customElements.define call errors on the page.

  • How do we target unknown tag names in the following scenarios?
    • When using querySelector(), closest(), and similar in JS
    • When using ::slotted(tag-name) in CSS
    • I really don't like adding a class to every host element at runtime — is there another o

This doesn't seem relevant, unless you're using @open-wc/scoped-elements@1.0.0. That version of the mixin didnt use the Scoped Custom Element Registries polyfill yet, and had a different scoping mechanism that adds a hash to the custom element tag name, and a data-tag-name= attribute to the element. So something like: <my-el-435245 data-tag-name="my-el"></my-el>. @open-wc/scoped-elements@2.0.0 uses scoped custom element registries, and no longer does this. Scoped elements are just defined by the name that you define them with, which means that querySelectors and css selectors etc should just work as is (for the shadowroot they are used in). It also doesnt add a class to every host at runtime.

KonnorRogers commented 1 year ago

Tabled for now, will revisit this in the future. We did add non-auto-registering imports.