ข้ามไปยังเนื้อหา

การใช้ใน Frameworks

custom element ที่ลงทะเบียนด้วย customElements.define คือ DOM node มาตรฐาน framework ใดก็ตามที่สร้าง HTML ก็ใช้ได้ คุณวางไว้ใน JSX, Vue template หรือ Angular template ได้เช่นเดียวกับที่คุณวาง <div>

เนื่องจาก frameworks สร้าง DOM nodes จริงในท้ายที่สุด ทุก framework จึงทำงานร่วมกับ custom elements ได้ในระดับเดียวกัน — element API ของ browser เอง Properties, attributes และ events ทำงานเหมือนกันโดยไม่ขึ้นกับ framework ที่เรนเดอร์ tree โดยรอบ

ใน React 18 และก่อนหน้านั้น custom elements รับ string attributes ไม่ใช่ rich object props ส่งค่า primitives (strings, numbers, booleans) เป็น attributes สำหรับข้อมูลที่ซับซ้อน (arrays, objects) หรือการฟัง custom events คุณต้องใช้ ref callback:

// React 18 — attach ref to wire up events
import { useRef, useEffect } from 'react';
function App() {
const ref = useRef(null);
useEffect(() => {
const el = ref.current;
el.addEventListener('my-event', (e) => console.log(e.detail));
return () => el.removeEventListener('my-event', () => {});
}, []);
return <my-counter ref={ref} label="Score"></my-counter>;
}

React 19 มาพร้อมการรองรับ custom element อย่างเต็มรูปแบบ Properties และ event handlers (ที่นำหน้าด้วย on) ตอนนี้ผูกกันโดยตรงโดยไม่ต้องใช้ ref workaround:

// React 19 — direct prop and event binding
function App() {
return (
<my-counter
label="Score"
count={0}
onmy-event={(e) => console.log(e.detail)}
/>
);
}

Vue ถือว่า custom elements เป็นพลเมืองชั้นหนึ่ง Attributes และ properties ผูกกันด้วย :prop="value" (property) หรือ attr="value" (attribute) Custom events ฟังด้วย @event-name:

<!-- Vue template -->
<my-counter
:label="label"
:count="score"
@score-changed="handleChange"
/>

Vue แยกแยะโดยอัตโนมัติว่าจะตั้งค่าเป็น property (set บน DOM node) หรือ attribute (set ผ่าน setAttribute) โดยดูจากว่า key นั้นมีอยู่ใน prototype ของ element หรือไม่

Angular รองรับ custom elements ผ่าน CUSTOM_ELEMENTS_SCHEMA เพิ่ม schema นี้เข้าไปใน array schemas ของ module เพื่อปิด error ของ unknown-element:

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@NgModule({
declarations: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}

ใน templates ใช้ [property] สำหรับ property binding และ (event-name) สำหรับ custom events:

<!-- Angular template -->
<my-counter [label]="title" [count]="score" (score-changed)="onScoreChanged($event)"></my-counter>

ตัวอย่างด้านล่างแสดง vanilla web component (<demo-badge>) ที่เรนเดอร์ใน HTML ธรรมดา — element เดียวกันนี้จะทำงานได้เหมือนกันทุกประการเมื่อวางใน React, Vue หรือ Angular tree เพราะเป็นแค่ DOM node

ตัวเลือกBenefitCost
ใช้ native interop ของ framework ตรงๆ (เช่น React 19 direct binding, Vue :prop)ไม่มี dependency เพิ่ม, bundle เล็กลง และใช้ API มาตรฐานของ browser ล้วนๆต้องจัดการ complex props/events เอง โดยเฉพาะบน React 18 ที่ต้องพึ่ง ref
ใช้ wrapper library เช่น @lit/reactได้ typed component พร้อม props/events ที่ผูกให้อัตโนมัติ ลด boilerplate ฝั่งผู้ใช้เพิ่ม dependency และ layer พิเศษที่ต้องดูแลให้ตรงกับเวอร์ชันของ element เดิม
  • สร้าง wrapper component ขึ้นมาเองทั้งที่ framework รองรับ native interop อยู่แล้ว (เช่น React 19) — เพิ่ม layer และโค้ดดูแลรักษาที่ไม่จำเป็น ทั้งที่ผูก property/event ตรงได้เลย
  • ส่ง array/object เป็น JSX attribute บน React 18 แล้วงงว่าทำไมค่าไม่ถูกต้อง — React 18 และก่อนหน้าจะแปลงทุกอย่างเป็น string attribute ต้องใช้ ref ตั้งค่า property โดยตรง หรืออัปเกรดเป็น React 19
  • ผูก custom event ด้วย attribute syntax ปกติแทน syntax เฉพาะของ framework — ลืมใช้ @event-name ใน Vue หรือ (event-name) ใน Angular ทำให้ event handler ไม่ถูกเรียกเลย

💡 ตัวอย่างจากของจริง

Google Material Web — เอกสารของโปรเจกต์สาธิตการใช้ component เดียวกันข้าม React, Angular และ Vue โดยไม่ต้องเขียน wrapper แยกสำหรับแต่ละ framework

Home Assistant — ฝัง custom elements ที่สร้างจาก Lit ไว้ใน dashboard UI ที่ผสมกับโค้ด frontend อื่นๆ ได้โดยตรงผ่าน native DOM interop

ใน React 18 วิธีที่แนะนำในการฟัง custom event ที่ถูกยิงจาก web component คืออะไร?
Vue ใช้อะไรในการตัดสินใจว่าจะตั้งค่าเป็น DOM property หรือ HTML attribute บน custom element?
Angular module token ใดที่อนุญาตให้ใช้ tag names ของ custom element โดยไม่เกิด compile error?