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 ofsomeProp
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
orReact.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