Search code examples
javascriptvue.jsvuejs3web-component

Expose method creating a web-component using Vue3


I am creating a web-component using VueJS 3, I want to expose a method on the component allowing the user to do something like this:

  <custom-component id="x1" />

  <script>
    var component = document.getElementById("x1");
    
    component.customMethod(); // as focus() method on native elements
  </script>

If I define a method on the component, I can call the method inside the component. But the method is not available when I use it as a web-component.

  //main.ts/js
  import { defineCustomElement } from "vue"
  import component from "./component.ce.vue"

  const element = defineCustomElement(component );

  customElements.define("custom-component ", element);
  //component.ce.vue
  const customMethod = () => { console.log("Executed"); }

How I can indicate to Vue Component Wrapper that the customMethod will be available outside the component?


Solution

  • In <script setup>, use the defineExpose() macro:

    <script setup>
    const customMethod = () => {⋯}
          👇
    defineExpose({ customMethod })
    </script>
    

    In the setup() hook, use the expose property of the context argument:

    <script>
    export default {   👇
      setup(props, { expose }) {
        const customMethod = () => {⋯}
          👇
        expose({ customMethod })
      }
    }
    </script>
    

    In the Options API, use the expose option:

    <script>
    export default {
         👇
      expose: ['customMethod'],
      methods: {
        customMethod() {⋯}
      }
    }
    </script>
    

    Currently (as of Vue 3.2.31), the only way to access the custom element's exposed properties is through its _instance.exposed property:

    <!-- example/index.html -->
    <body>
      <custom-component id="x1"></custom-component>
      <script>
        const el = document.getElementById('x1')
                       👇
        el._instance.exposed.customMethod()
      </script>
    </body>
    

    Since _instance is a private property, use this solution with caution, as the property could be renamed/removed in a future release.

    demo (<script setup>)

    demo (setup() hook)

    demo (Options API)