Subscribe on changes!

If I pass a "render function" to the "defineCustomElement" the slots are not displayed

avatar
Mar 7th 2023

Vue version

3.2.47

Link to minimal reproduction

https://codesandbox.io/p/sandbox/infallible-mclaren-4m5lg9

Steps to reproduce

Access the link

What is expected?

Three buttons should be visualized that are passed to the "web component" as "slot"

What is actually happening?

I am trying to create a "web component" with the vue 3.2 "defineCustomElement" utility.

The "defineCustomElement" must be passed a vue component or a "render function".

My problem is that, when using "slot", if I use the "defineCustomElement" passing a component if the "slot" is displayed but when using the "function render" it is never displayed. They don't have the same behavior and I need to use a wrapper where I render the component.

If the "slots" work:

customElements.define("hello-word-a", defineCustomElement(HelloWorld));

The "slots" do not work:

customElements.define( "hello-word-b", defineCustomElement({ props: HelloWorld.props, setup(props, { slots }) { return () => h(HelloWorld, { ...props }, slots); }, }) );

System Info

No response

Any additional comments?

No response

avatar
Mar 7th 2023

The Custom Elements standard does have slots, but the work differently than Vue slots. To receive content passed into the slots of a custom element, we have to mount an actual <slot></slot> element in the DOM.

If you choose to write your own render function, you need to do that yourself:

customElements.define(
  "hello-word-b",
  defineCustomElement({
    props: HelloWorld.props,
    setup(props, { slots }) {
      console.log(slots);
      return () =>
        h(
          HelloWorld,
          { ...props },
          {
            "slot-a": () => h("slot", { name: "slot-a" }),
          }
        );
    },
  })
);

@skirtles-code I think we could add a section in the docs about Custom Elements about this, WDYT?