Integrate Web Components with Your Vue.js App

Published on September 25, 2017
Default avatar

By Joshua Bemenderfer

Integrate Web Components with Your Vue.js App

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Even though the Web Components spec and implementations may not be considered to be mature by all, there are still quite a few interesting components and projects out there that you might find useful for your own purposes. That being said, Vue still offers a huge amount over plain’ol web components. (In fact, you can even make Web Components with Vue.) Well, why not have the best of both worlds? It’s actually really straightforward to use Web Components in Vue. Conditionals, properties, and even event bindings just keep working just like you’d expect them to.


(This guide assumes you’ve started a quick Vue.js project with vue-cli and the webpack-simple template.)

Let’s go ahead an create a simple web component that illustrates properties and events with as little code as possible…

Behold: The ticking paragraph! Basically, it’s a wrapper for a paragraph. You set its text content through the content attribute. Oh, and it emits a tick event every half second or so for some reason. Yes, I lack creativity and / or the capability to come up with anything practical. Moving on.

<template id="x-ticking-paragraph">
    p {
      color: #42b983;
  <p id="renderTarget">

  const currentScript = document.currentScript;

  customElements.define('x-ticking-paragraph', class extends HTMLElement {
    static get observedAttributes() { return ['contents'] }

    constructor() {
      let shadowRoot = this.attachShadow({mode: 'open'});
      const template = currentScript.ownerDocument.querySelector('#x-ticking-paragraph');
      const instance = template.content.cloneNode(true);

      this.contents = '';

      setInterval(() => {
        this.dispatchEvent(new Event('tick'));
      }, 500);

    set contents(value) {
      this._contents = value;
      this.shadowRoot.getElementById('renderTarget').innerText = this._contents;

    get contents() {
      return this._contents;

    attributeChangedCallback(name, oldValue, newValue) {
      this[name] = newValue;

I know, I know. I’m using the old HTML-imports style of component here because it feels more elegant… for a more civilized age. Also it totally looks like a Vue Single File Component doesn’t it? (Vue was inspired in part by the original Web Components spec.)

I’m not going to explain it all here, rather, if you’d like to see how to create a more proper Web Component for Modern Times™, we’ve covered that too.

Alright, so now we need to load it into the page somehow. We’ll also grab a polyfill along the way so this works in more browsers than just Chrome.

<!DOCTYPE html>
<html lang="en">
    <meta charset="utf-8">
    <title>Vue + Web Components</title>
    <!-- Web Components Polyfill -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/1.0.13/webcomponents-lite.js"></script>
    <!-- Loading our component -->
    <link rel="import" href="./ticking-paragraph.html">
    <div id="app"></div>
    <script src="/dist/build.js"></script>

Now that we’ve done all that, we can finally use our component in Vue as stated by the title directly following this paragraph.

Using Your Component In Vue

Really the only thing we have to do to make Vue work with this component is whitelist it in Vue.config.ignoredElements. This just tells Vue that the element / component comes from a source that Vue doesn’t know about, and keeps the compiler from complaining.

import Vue from 'vue';
import App from './App.vue';

Vue.config.ignoredElements = [

new Vue({
  el: '#app',
  render: h => h(App)

Now, use the component like any other! Reactivity stays intact!

  <div id="app">
    <h1>Vue ❤ Web Components</h1>
    <x-ticking-paragraph :contents="paragraphContents" @tick="logTick"></x-ticking-paragraph>

export default {
  data() {
    return {
      paragraphContents: `I'm data from Vue rendering in a Web Component!`

  methods: {
    logTick() {
      console.log(`The paragraph ticked again. >_>`)

The best part is, you don’t need to make any changes to the Web Component or to your Vue app to somehow force them to grudginly work together. It works right out of the box! In fact, you can even integrate elements that internally use other frameworks like Polymer or React.

Now, how useful this ends up being to you depends entirely on whether or not you are (or want to be) using Web Components alongside Vue. That said, if nothing else, it does indicate that if Web Components are the future, Vue is future-proof.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us

About the authors
Default avatar
Joshua Bemenderfer


Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
Leave a comment

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel