Teknologi

Menggunakan Web Components di React, Angular, dan Vue

Ingin komponen UI Anda bisa dipakai di mana saja, tanpa terikat framework? Pelajari Cara Menggunakan Web Components di React, Angular, dan Vue! Bikin komponen reusable, terenkapsulasi, & future-proof dengan panduan lengkap ini.

rezki kurniawan28 Juli 2025

Web Components adalah standar web yang memungkinkan Anda membuat custom, reusable, encapsulated HTML tags (elemen HTML kustom) yang bekerja di semua modern browser. Mereka bersifat agnostik terhadap framework JavaScript, artinya Anda bisa menggunakannya di mana saja — di proyek Vanilla JavaScript, atau bahkan di dalam framework seperti React, Angular, atau Vue.

Mengintegrasikan Web Components ke dalam framework JS populer bisa menjadi cara yang ampuh untuk:

  1. Membangun Sistem Desain yang Agnostik Framework: Komponen inti dapat dibagikan di berbagai proyek yang menggunakan framework berbeda.

  2. Meningkatkan Reusability: Komponen UI yang kompleks bisa dienkapsulasi dan digunakan kembali tanpa dependensi framework.

  3. Mengintegrasikan Legacy Code: Menggabungkan elemen dari aplikasi lama yang dibangun dengan teknologi berbeda.

  4. Isolasi Gaya (Shadow DOM): Gaya CSS dalam Web Component tidak akan "bocor" keluar dan memengaruhi bagian lain dari aplikasi, dan sebaliknya.

Mari kita lihat bagaimana cara menggunakan Web Components di React, Angular, dan Vue.

Dasar-dasar Web Components

Sebelum menyelam ke dalam framework, pahami tiga pilar utama Web Components:

  1. Custom Elements: Memungkinkan Anda mendefinisikan tag HTML kustom (misalnya, <my-button>).

  2. Shadow DOM: Menyediakan mekanisme enkapsulasi untuk markup dan gaya di dalam komponen, mengisolasi mereka dari sisa dokumen.

  3. HTML Templates: Elemen <template> dan <slot> memungkinkan Anda mendefinisikan markup yang dapat di-render ulang dan mendistribusikan konten anak ke dalam Shadow DOM.

Biasanya, Anda akan menggunakan library kecil seperti Lit (dari Google) atau Stencil (dari Ionic) untuk mempermudah pembuatan Web Components, meskipun Anda bisa membangunnya dengan Vanilla JS. Untuk panduan ini, kita akan asumsikan Anda memiliki Web Component dasar yang siap digunakan, misalnya:

HTML

<script>
  class MyHelloComponent extends HTMLElement {
    constructor() {
      super();
      const shadowRoot = this.attachShadow({ mode: 'open' }); // 'open' agar bisa diakses dari JS luar
      const template = document.createElement('template');
      template.innerHTML = `
        <style>
          .wrapper {
            padding: 10px;
            border: 1px solid blue;
            border-radius: 5px;
            background-color: lightblue;
          }
          ::slotted(p) {
            font-style: italic;
          }
        </style>
        <div class="wrapper">
          <p>Halo dari Web Component!</p>
          <slot name="subtitle"></slot> <slot></slot> </div>
      `;
      shadowRoot.appendChild(template.content.cloneNode(true));
    }

    connectedCallback() {
      // Dipanggil saat elemen ditambahkan ke DOM
      console.log('MyHelloComponent added to DOM');
    }

    disconnectedCallback() {
      // Dipanggil saat elemen dihapus dari DOM
      console.log('MyHelloComponent removed from DOM');
    }
  }

  customElements.define('my-hello-component', MyHelloComponent);
</script>

Anda akan mengimpor file JavaScript ini ke proyek Anda agar browser dapat mendaftarkan custom element.

1. Menggunakan Web Components di React

React memperlakukan Web Components sebagian besar seperti elemen HTML standar. Tantangan utama ada pada penanganan event kustom dan properti kompleks.

a. Mengimpor Web Component: Pastikan Web Component Anda diimpor dan terdaftar sebelum komponen React Anda mencoba menggunakannya. Anda bisa melakukannya di index.js atau App.js Anda.

JavaScript

// src/index.js atau src/App.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './my-hello-component'; // Pastikan jalur ke file Web Component Anda benar

// ... sisa kode aplikasi React Anda

b. Meneruskan Props: React akan meneruskan props ke Web Component sebagai atribut HTML secara default. Ini berarti Anda harus memastikan Web Component Anda siap membaca nilai dari atribut.

JavaScript

// src/components/MyReactComponent.jsx
import React from 'react';
import '../my-hello-component'; // Pastikan Web Component sudah terdaftar

function MyReactComponent() {
  const handleClick = (event) => {
    // Tangani event klik di sini
    console.log('Web Component diklik!', event);
  };

  return (
    <div>
      <h3>Integrasi Web Component di React</h3>
      {/* Meneruskan props sebagai atribut */}
      <my-hello-component
        my-custom-attr="nilai-atribut-kustom"
        data-id="123"
        // Untuk event kustom, gunakan useRef atau event listener manual jika perlu
        onClick={handleClick} // Event standar HTML akan bekerja
      >
        {/* Menggunakan slot default */}
        <p>Ini adalah konten yang dimasukkan ke slot default.</p>
        {/* Menggunakan slot bernama */}
        <span slot="subtitle">Subtitle dari React!</span>
      </my-hello-component>

      <hr />

      {/* Jika Web Component memiliki properti kompleks (objek/array) */}
      {/* React mungkin tidak menanganinya sebagai atribut secara otomatis. */}
      {/* Anda perlu useRef dan useEffect untuk mengatur properti secara manual. */}
      <web-component-with-complex-props ref={el => {
        if (el) {
          el.complexData = { key: 'value', arr: [1, 2, 3] };
        }
      }}></web-component-with-complex-props>
    </div>
  );
}

export default MyReactComponent;

c. Menangani Event Kustom: Ini adalah area yang sedikit rumit. React akan secara otomatis mendengarkan event HTML standar (seperti click, change). Namun, jika Web Component Anda memancarkan event kustom (misalnya, detailChanged), React mungkin tidak menangkapnya secara otomatis.

Anda perlu menambahkan event listener secara manual menggunakan useRef dan useEffect:

JavaScript

// src/components/MyReactComponentWithCustomEvent.jsx
import React, { useRef, useEffect } from 'react';
import '../my-custom-event-component'; // Misalkan ini Web Component Anda

function MyReactComponentWithCustomEvent() {
  const webComponentRef = useRef(null);

  useEffect(() => {
    const handleCustomEvent = (event) => {
      console.log('Custom event diterima dari Web Component:', event.detail);
      // Lakukan sesuatu dengan data event.detail
    };

    const currentComponent = webComponentRef.current;
    if (currentComponent) {
      // Tambahkan event listener untuk event kustom 'myCustomEvent'
      currentComponent.addEventListener('myCustomEvent', handleCustomEvent);
    }

    // Cleanup function: Hapus event listener saat komponen dilepas
    return () => {
      if (currentComponent) {
        currentComponent.removeEventListener('myCustomEvent', handleCustomEvent);
      }
    };
  }, []); // [] agar hanya berjalan sekali saat mount

  return (
    <div>
      <h3>Web Component dengan Event Kustom di React</h3>
      <my-custom-event-component ref={webComponentRef}></my-custom-event-component>
    </div>
  );
}

export default MyReactComponentWithCustomEvent;

2. Menggunakan Web Components di Angular

Angular memiliki dukungan yang sangat baik untuk Web Components berkat fleksibilitasnya dalam bekerja dengan elemen DOM kustom. Anda perlu mengonfigurasi Angular untuk mengenali elemen kustom.

a. Mengimpor Web Component: Impor file JavaScript Web Component Anda, biasanya di main.ts atau file entry utama.

TypeScript

// src/main.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

// Impor file Web Component Anda.
// Ini akan mendaftarkan custom element di browser.
import './my-hello-component';

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

b. Memberi Tahu Angular untuk Mengabaikan Elemen Kustom: Angular secara default akan mengeluarkan peringatan untuk tag HTML yang tidak dikenalnya. Untuk mencegah ini, tambahkan CUSTOM_ELEMENTS_SCHEMA ke module Anda.

TypeScript

// src/app/app.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent],
  schemas: [CUSTOM_ELEMENTS_SCHEMA] // Tambahkan ini
})
export class AppModule { }

c. Meneruskan Props dan Menangani Event: Angular memperlakukan atribut dan event Web Component dengan cara yang sangat mirip dengan elemen HTML standar.

HTML

<div>
  <h2>Integrasi Web Component di Angular</h2>
  <my-hello-component
    my-custom-attr="nilai-dari-angular"
    [data-id]="angularDataId"       (standard-event)="handleStandardEvent($event)" (customEvent)="handleCustomEvent($event.detail)" >
    <p>Ini adalah konten dari Angular ke slot default.</p>
    <span slot="subtitle">Subtitle dari Angular!</span>
  </my-hello-component>
</div>

TypeScript

// src/app/app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular-web-components-example';
  angularDataId = 'ABC';

  handleStandardEvent(event: Event) {
    console.log('Event standar diterima dari Web Component (Angular):', event);
  }

  handleCustomEvent(detail: any) {
    console.log('Event kustom diterima dari Web Component (Angular):', detail);
    // 'detail' akan berisi payload dari CustomEvent.detail
  }
}

3. Menggunakan Web Components di Vue

Vue.js, terutama Vue 3, memiliki dukungan yang sangat baik untuk Web Components dan akan secara otomatis mengenali elemen kustom.

a. Mengimpor Web Component: Impor file JavaScript Web Component Anda di main.js atau file entry lainnya.

JavaScript

// src/main.js
import { createApp } from 'vue';
import App from './App.vue';

import './my-hello-component'; // Pastikan jalur ke file Web Component Anda benar

createApp(App).mount('#app');

b. Meneruskan Props: Vue akan meneruskan props ke Web Component sebagai atribut HTML secara default. Untuk properti yang bukan string (misalnya, objek atau array), Anda mungkin perlu mengikatnya sebagai properti DOM menggunakan . modifier.

Code snippet

<template>
  <div>
    <h2>Integrasi Web Component di Vue</h2>
    <my-hello-component
      my-custom-attr="nilai-dari-vue"
      :data-id="vueDataId"
      @click="handleClick"                  @customEvent="handleCustomEvent"      :complex-prop.prop="complexObject"    >
      <p>Ini adalah konten dari Vue ke slot default.</p>
      <span slot="subtitle">Subtitle dari Vue!</span>
    </my-hello-component>
  </div>
</template>

<script>
import './my-hello-component'; // Pastikan Web Component sudah terdaftar

export default {
  name: 'App',
  data() {
    return {
      vueDataId: 'XYZ',
      complexObject: { message: 'Halo dari Vue' },
    };
  },
  methods: {
    handleClick(event) {
      console.log('Web Component diklik (Vue)!', event);
    },
    handleCustomEvent(event) { // Vue secara otomatis "membuka" event.detail
      console.log('Custom event diterima dari Web Component (Vue):', event);
      // 'event' di sini adalah event.detail langsung jika Web Component memancarkan CustomEvent
    },
  },
};
</script>

c. Penanganan Event Kustom: Vue 3 secara otomatis akan "membuka" objek CustomEvent dari Web Component, sehingga Anda dapat mengakses event.detail secara langsung sebagai argumen pertama ke handler Anda. Ini sangat nyaman.

d. Mengabaikan Resolusi Komponen (Opsional, untuk Vue 2): Untuk Vue 2, jika Anda menemui peringatan "Unknown custom element", Anda mungkin perlu mengonfigurasi Vue.config.ignoredElements:

JavaScript

// main.js (untuk Vue 2)
import Vue from 'vue';
import App from './App.vue';

// Abaikan elemen kustom
Vue.config.ignoredElements = [
  'my-hello-component',
  /^my-prefix-/ // Atau regex untuk semua custom element dengan prefix tertentu
];

import './my-hello-component'; // Pastikan Web Component sudah terdaftar

new Vue({
  render: h => h(App),
}).$mount('#app');

Untuk Vue 3, ini biasanya tidak diperlukan karena Vue 3 memiliki heuristik runtime untuk mengenali elemen kustom.

Pertimbangan Umum Saat Menggunakan Web Components di Frameworks

  • Server-Side Rendering (SSR): Web Components mengandalkan DOM, yang tidak ada di lingkungan SSR. Ini bisa menjadi tantangan. Anda mungkin perlu melakukan hydration atau penanganan khusus untuk Web Components pada saat client-side.

  • Properti Kompleks vs. Atribut: Ingat bahwa atribut HTML hanya dapat menyimpan string. Untuk properti yang kompleks (objek, array), Anda harus mengatur properti langsung pada elemen DOM kustom (misalnya, el.propertyName = value;) setelah komponen Web Component di-render oleh framework. Gunakan ref di React, atau referensi template di Angular/Vue.

  • Performa: Menggunakan Web Components di dalam framework umumnya tidak akan memberikan peningkatan performa yang drastis, tetapi juga tidak akan merusaknya secara signifikan. Fokus utamanya adalah reusability dan interoperability.

  • Styling: Ingat bahwa Shadow DOM mengisolasi gaya. Jika Anda perlu menata gaya Web Component dari luar, Web Component harus mengekspos CSS custom properties (variabel CSS) atau menggunakan CSS parts.

  • Perbandingan dengan Komponen Framework: Web Components berguna untuk komponen agnostik framework. Namun, jika Anda hanya membangun satu aplikasi dengan satu framework, membuat komponen bawaan framework (misalnya, komponen React murni) mungkin lebih mudah karena integrasi yang lebih mulus dengan state management, lifecycle, dan tooling framework.

Menggunakan Web Components di dalam framework JavaScript modern adalah bukti kekuatan dan fleksibilitas ekosistem web. Ini memungkinkan developer untuk membangun platform-agnostic components dan menciptakan sistem desain yang lebih modular dan future-proof.

Share:

0 Komentar

Artikel Terkait