Web Components and Framework Integration Vue & React Case Study



This content originally appeared on DEV Community and was authored by Tianya School

For a long time, I dreamed of building a fully customizable, reusable, and cross-framework UI component library to streamline my project development. By chance, I discovered Web Components, a native Web API that allows the creation of custom HTML tags for component-based development. Excited by its potential, I decided to integrate Web Components with popular frontend frameworks—React and Vue—in my latest project to explore the possibilities of this combination.

Early in the project, I was captivated by the power of Web Components. Supported natively by browsers, they require no external libraries or frameworks and offer full encapsulation, enabling components to be used independently anywhere.

Web Components Integration with Vue

Integrating Web Components with Vue.js typically involves creating and using custom elements within a Vue application while preserving Vue’s data binding and lifecycle methods.

Installing @vue/web-component-wrapper

npm install --save @vue/web-component-wrapper

Suppose we have a Vue component named MyVueComponent.vue:

MyVueComponent.vue

<template>
  <div>
    <p>{{ message }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello from Vue Component'
    };
  },
  methods: {
    increment() {
      this.message = 'Count incremented!';
    }
  }
};
</script>

Next, we can use @vue/web-component-wrapper to convert this Vue component into a Web Component:

index.js

import Vue from 'vue';
import MyVueComponent from './MyVueComponent.vue';
import VueWebComponentWrapper from '@vue/web-component-wrapper';

Vue.customElement('my-vue-component', MyVueComponent);

// Alternatively, if you want to use LitElement as a base:
// import { LitElement, html } from 'lit-element';
// import { wrap } from '@vue/web-component-wrapper';
// import MyVueComponent from './MyVueComponent.vue';

// class MyCustomElement extends LitElement {
//   render() {
//     return html`
//       <my-vue-component></my-vue-component>
//     `;
//   }
// }

// wrap(Vue, MyCustomElement, MyVueComponent);

customElements.define('my-vue-component', VueWebComponentWrapper(MyVueComponent));

Now, you can use the <my-vue-component> tag anywhere Web Components are supported, like this:

index.html

<!DOCTYPE html>
<html>
<head>
  <title>Vue Web Component</title>
</head>
<body>
  <my-vue-component></my-vue-component>
  <script src="index.js"></script>
</body>
</html>

The Vue component MyVueComponent is transformed into a Web Component, retaining its internal data binding and methods. In an external HTML file, you can use the <my-vue-component> tag without importing the entire Vue library.

Vue Page (App.vue)

<template>
  <div>
    <my-vue-component></my-vue-component>
  </div>
</template>

<script>
export default {
  name: 'App'
};
</script>

Web Components Integration with React

Web Components can be used directly in React applications since they are natively supported by browsers, independent of specific frameworks.

Web Component (MyCustomElement.js)

import { LitElement, html, css } from 'lit-element';

class MyCustomElement extends LitElement {
  static get styles() {
    return css`
      /* Custom styles */
    `;
  }

  static get properties() {
    return {
      someProp: { type: String },
    };
  }

  constructor() {
    super();
    this.someProp = 'Default value';
  }

  _handleClick() {
    this.dispatchEvent(new CustomEvent('custom-event', { detail: 'Hello from LitElement' }));
  }

  render() {
    return html`
      <button @click="${this._handleClick}">Click me</button>
      <p>${this.someProp}</p>
    `;
  }
}

customElements.define('my-custom-element', MyCustomElement);

React Component (App.js)

import React from 'react';

function App() {
  const handleCustomEvent = (event) => {
    console.log('Custom event received:', event.detail);
  };

  return (
    <div>
      <my-custom-element some-prop="React Value" on-custom-event={handleCustomEvent}></my-custom-element>
    </div>
  );
}

export default App;

Key Considerations for Using Web Components in React

  • Property Binding: React uses camelCase for properties, while Web Components use kebab-case. In React, use some-prop instead of someProp for attribute binding.
  • Event Listening: React’s JSX @event syntax doesn’t directly map to Web Component event listeners. React attaches event listeners to the outermost DOM element, so @custom-event listens on the React component’s root, not directly on the Web Component. If the Web Component’s events don’t bubble, handle them within the Web Component itself.
  • State Management and Updates: React’s state management and component update mechanisms differ from Web Components. Web Component state changes won’t trigger React re-renders.
  • Lifecycle Methods: React’s lifecycle methods don’t fully align with Web Components’ lifecycles. Coordination may be needed for operations tied to specific lifecycle stages.
  • Performance Considerations: Since React doesn’t directly manage Web Components, additional optimizations like shouldComponentUpdate or React.memo may be required to minimize unnecessary renders.

🎁 I have compiled a complete series of advanced programming collections on Patreon:

  • Weekly updated technical tutorials and project practice
  • High-quality programming course PDF downloads
  • Front-end / Back-end / Full Stack / Architecture Learning Collection
  • Subscriber Exclusive Communication Group

👉 Click to join and systematically improve development capabilities: Advanced Development Tutorial


This content originally appeared on DEV Community and was authored by Tianya School