Web Component + Vue

It is actually straightforward to use standard Web Components within a Vue application. The bindings and events still work as one would expect.

About

The simple web component project I created illustrates the use of a web component within Vue. The component I wrote consists of a counter and a button to increase the value by one. Maybe not a real world component, but it shows some core component concepts.

The initial value is set by an element attribute and the component uses events to update the parents in case of value change.

Currently all modern browsers support Web Components and with the help of polyfills even older browsers like Internet Explorer 11 and others are supported.

The Webcomponent

Create the Web Component (full source code is at GitHub).

New to Web Components? See this excellent introduction into Web Components at Alligator.io: Your First Custom Element

 
class IncrementButton extends HTMLElement {
    constructor() {
        super();

        // Scoped CSS by using shadow DOM.
        this.attachShadow({mode: 'open'});
        this.shadowRoot.innerHTML = `
        

        <style>
          div {
            font-weight: bold;
          }
          button {
            border: 1px solid blue;
            background-color: lightblue;
            color: black;
            padding: .5em 1em;
            margin-left: .5em;
          }
        </ style>
        <div>
            increment: <span class="value"></span>
            <button type="button" increment>+</button>
        </div>`;

        this.incrementBtn = this.shadowRoot.querySelector('[increment]');
        this.displayValue = this.shadowRoot.querySelector('.value');

        // Bind the increment function to the html element 
        // object context (instead of the calling context).
        this.increment = this.increment.bind(this);
    }
}
window.customElements.define('increment-button', IncrementButton);

On component creation we have to register a listener on the button. And on destroy of the component we have to remove this listener again to prevent memory leaks.

 

/**
 * Initially called on element creation.
 * Register listener for button.
 */
connectedCallback() {
    this.incrementBtn
      .addEventListener('click', this.increment);
}

/**
 * Called on element destroy.
 */
disconnectedCallback() {
    this.incrementBtn
      .removeEventListener('click', this.increment);
}

/**
 * Increment the value by one.
 */
increment() {
    this.value = +this.value + 1;
}

On change of the value, we propagate the change to the parents with an event.

Also we update the attribute of our element so the value attribute always mirrors the internal value.


/**
 * Set the value.
 * @param {number|string} newValue The numeric value
 */
set value(newValue) {
    this.setAttribute('value', newValue);
    this.dispatchEvent(new CustomEvent("update:value", {detail: +newValue}));
}

Within Vue

We can treat the Web Component just like any other HTML element in Vue.

In the code below we bind the vue variable named ‘value’ to the Web Components value attribute. On update event, we update the Vue variable with the new value.


<div>
  <increment-button 
      :value="value" 
      @update:value="value = $event.target.value">
  </increment-button>
</div>

Demo

See the Web Component in action: https://sandbox.juurlink.org/webcomponent-vue/

Resources

I used these blog posts as primary source for my code.

The source code is hosted at GitHub.

https://github.com/kozmoz/webcomponent-vue

And a live demo is here.

https://sandbox.juurlink.org/webcomponent-vue/

Leave a Reply

Your email address will not be published. Required fields are marked *