Vue in Custom Element

Published on 2019-12-28 15:57

As a part of Sloth project I came across the need to embed Vue into a page as a widget. As it has been more of a struggle than expected this post needed to be written.

First step to do in making Vue embeddable is to change build target. The default build target created by Vue CLI is meant to be deployed as an SPA. In order to build widget enclosed by a custom element we need to add target flag:

--target wc

wc   is an abbreviation for Web Component.

As the next step we need to decide whether Vue should be inlined or not. Inlining means that Vue is included in final JavaScript file. This is useful when we plan to have only one Vue widget on the page because only one file will have to be linked. On the other hand inline flag isn't useful on a page with several widgets.

In case we choose to inline, we'll add flag:


As the last thing with the tooling we need to add name of the tag:

--name my-tag

When it's all put together, build  target in package.json  looks like:

// ...
"build": "vue-cli-service build --target wc --inline-vue --name my-tag",
// ...

The main change in the code is that main.ts or JavaScript equivalent is no longer the entry file for our application. The role of entry file is assigned to the first component, usually App.vue . So when we need to use tools like Vuex we have to import them there instead of in the main file. So TypeScript part of my App.vue  looks like this:

import { Component, Vue } from "vue-property-decorator";

import store from "./store";

import HelloWorld from "./components/HelloWorld.vue";

export default {

store, name: "App", props: ["token"], components: { HelloWorld } };

Now we are ready to build and deploy things. As you can see we have there a prop token  which we can use on the page as an attribute:

<my-tag token="Hello"></my-tag>

To be able to work with props during development we need to edit main.ts because serve target wasn't changed. The default render function contains only App argument, so to pass props we need to add second argument, object containing token prop.

render: (h) => h(App, { props: { 'token': 'Hello' } })

Now we are ready to make widgets in Vue.js.

Note: As this widget uses Custom Elements, please, be aware that it won't work in IE11.