Customized Built-ins
custom element สองแบบ
หัวข้อที่มีชื่อว่า “custom element สองแบบ”สเปกของ Web Components นิยาม custom element ไว้สองแบบ:
| แบบ | extend จาก | ลงทะเบียนเป็น | ใช้ใน HTML |
|---|---|---|---|
| Autonomous | HTMLElement | customElements.define('x-btn', XBtn) | <x-btn> |
| Customized built-in | เช่น HTMLButtonElement | customElements.define('x-btn', XBtn, { extends: 'button' }) | <button is="x-btn"> |
Customized built-ins: ไวยากรณ์
หัวข้อที่มีชื่อว่า “Customized built-ins: ไวยากรณ์”customized built-in extend จาก class ของ HTML element ตัวใดตัวหนึ่งโดยเฉพาะ และประกาศว่า extend element ที่มีมาในตัวตัวใดในอาร์กิวเมนต์ตัวที่สามของ define:
class FancyButton extends HTMLButtonElement { connectedCallback() { this.style.background = '#4f46e5'; this.style.color = '#fff'; this.style.borderRadius = '6px'; this.style.padding = '.4rem 1rem'; this.style.border = 'none'; this.style.cursor = 'pointer'; }}
customElements.define('fancy-button', FancyButton, { extends: 'button' });ใน HTML attribute is จะเปิดใช้ customized built-in บน element มาตรฐาน:
<button is="fancy-button">Click me</button>element นี้ยังคงเป็น <button> อยู่ — จึงสืบทอด semantics ที่มีมาในตัวทั้งหมด (โฟกัสได้ ส่ง form ได้ ตอบสนองต่อ disabled) บวกกับพฤติกรรมที่คุณกำหนดเอง
ข้อควรระวังเรื่องการรองรับ
หัวข้อที่มีชื่อว่า “ข้อควรระวังเรื่องการรองรับ”Safari ไม่รองรับ customized built-ins และได้ปฏิเสธอย่างชัดเจนว่าจะไม่รองรับ นี่เป็นปัญหาด้านการพกพาที่สำคัญ: <button is="fancy-button"> จะถูกเรนเดอร์เป็นปุ่มธรรมดาที่ไม่มีสไตล์ใน Safari
มี polyfill อยู่ (เช่น @ungap/custom-elements) แต่เพิ่มน้ำหนักและความซับซ้อน
<!-- This renders correctly in Chrome/Firefox but NOT in Safari: --><button is="fancy-button">Safari renders this as a plain button</button>ตัวเลือกที่พกพาได้: autonomous elements
หัวข้อที่มีชื่อว่า “ตัวเลือกที่พกพาได้: autonomous elements”autonomous custom elements (extends HTMLElement) ได้รับการรองรับอย่างเต็มที่ในทุกที่ สำหรับตัวอย่างปุ่ม นี่คือ autonomous element ที่เทียบเท่ากัน:
class XButton extends HTMLElement { connectedCallback() { this.innerHTML = '<button style="background:#4f46e5;color:#fff;border-radius:6px;' + 'padding:.4rem 1rem;border:none;cursor:pointer">' + (this.textContent || 'Click me') + '</button>'; }}customElements.define('x-button', XButton);คุณจะเสียการสืบทอด semantics ของ <button> เนทีฟแบบอัตโนมัติไป (คุณต้องเพิ่ม role="button" และจัดการคีย์บอร์ดด้วยตัวเอง) แต่คุณจะได้การรองรับข้าม browser อย่างเต็มที่
เดโมที่รันได้ (autonomous element)
หัวข้อที่มีชื่อว่า “เดโมที่รันได้ (autonomous element)”เดโมด้านล่างใช้ autonomous element — ทำงานได้ในทุก browser ส่วนไวยากรณ์ของ customized built-in แสดงไว้เพื่อเป็นข้อมูลอ้างอิงเท่านั้น
หมายเหตุเรื่อง browser: รูปแบบ customized built-in (
class extends HTMLButtonElement+<button is="...">) ไม่รองรับใน Safari ให้ใช้ autonomous elements (class extends HTMLElement) เพื่อให้ได้ Web Components ที่พกพาได้และทำงานข้าม browser
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
Customized built-in (is="...") | สืบทอด semantics เนทีฟของ element เดิมได้ครบ (focus, form submission, accessibility) โดยไม่ต้องเขียนเอง | Safari ปฏิเสธที่จะรองรับอย่างถาวร ทำให้พกพาข้าม browser ไม่ได้ |
Autonomous element (extends HTMLElement) | รองรับเต็มรูปแบบในทุก browser หลัก | ต้องเขียน semantics ที่เนทีฟให้ฟรี (เช่น role, keyboard handling) ด้วยตัวเอง |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- ลืมใส่
{ extends: 'button' }— ถ้าไม่ส่ง option ตัวที่สามให้customElements.definebrowser จะไม่รู้ว่านี่คือ customized built-in และis="fancy-button"จะไม่ทำงาน - ไม่ทดสอบใน Safari ก่อน deploy — ความล้มเหลวเป็นแบบเงียบ ไม่มี error ใน console แค่เรนเดอร์เป็น
<button>ธรรมดาไม่มีสไตล์ ทำให้พลาดง่ายถ้าทดสอบแค่ Chrome/Firefox - ใส่ polyfill โดยไม่ชั่งน้ำหนักต้นทุน —
@ungap/custom-elementsช่วยแก้ปัญหาได้ แต่เพิ่ม bundle size และความซับซ้อนให้ทุก request แม้ใน browser ที่รองรับอยู่แล้ว
💡 ตัวอย่างจากของจริง
GitHub — เลือกสร้าง
<relative-time>และ<clipboard-copy>เป็น autonomous elements แทนที่จะใช้ customized built-ins เพื่อให้ทำงานได้ในทุก browser รวมถึง SafariAdobe Spectrum — ดีไซน์ระบบ Spectrum Web Components เลือกใช้ autonomous elements เป็นหลักด้วยเหตุผลด้านการพกพาข้าม browser เดียวกันนี้