Default Slot
default slot ทำงานอย่างไร
หัวข้อที่มีชื่อว่า “default slot ทำงานอย่างไร”<slot> element ที่ไม่มี name attribute คือ default slot ลูกทั้งหมดใน light DOM ที่ ไม่มี slot attribute จะถูกกระจายไปอยู่ที่นั่น คุณวาง <slot> ไว้ภายใน shadow root ของคุณ แล้ว browser จะจัดการ render เนื้อหาลูกที่ถูกฉายเข้ามาให้ที่ตำแหน่งนั้น
<my-box> <p>This paragraph is projected into the default slot.</p></my-box>class MyBox extends HTMLElement { connectedCallback() { const shadow = this.attachShadow({ mode: 'open' }); shadow.innerHTML = ` <style> :host { display: block; border: 2px solid #6366f1; padding: 1rem; border-radius: 8px; } </style> <slot><em>No content provided</em></slot> `; }}customElements.define('my-box', MyBox);Fallback content
หัวข้อที่มีชื่อว่า “Fallback content”เนื้อหาที่วาง ภายใน <slot> element เองคือ fallback จะ render ก็ต่อเมื่อไม่มีเนื้อหาลูกจาก light DOM ถูกฉายเข้าไปใน slot นั้น หากผู้ใช้งานใส่ลูกเข้ามา fallback จะถูกซ่อน หากไม่ได้ใส่ลูกใด ๆ fallback จะแสดงขึ้นมา
นี่เป็นวิธีที่ไม่มีต้นทุนในการทำให้คอมโพเนนต์อธิบายตัวเองได้ ตัว fallback text จะบอกว่าผู้ใช้งานควรจะใส่อะไรเข้ามา
การฉายเข้า slot ไม่ใช่การคัดลอก
หัวข้อที่มีชื่อว่า “การฉายเข้า slot ไม่ใช่การคัดลอก”ลูกใน light DOM ยังคงอยู่ใน light DOM มีเพียง ตำแหน่งการ render เท่านั้นที่ย้ายไปอยู่ที่ slot ตัว node ไม่ได้ถูก clone หรือย้ายไปไหน ตัวอย่างเช่น document.querySelector('my-box').firstChild ยังคงคืนค่า <p> element แม้ว่าจะถูกฉายเข้าไปใน shadow root แล้วก็ตาม event listener ที่ผูกไว้กับ node ใน light DOM ก็ยังทำงานได้ตามปกติ
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
| Default slot เดี่ยว | เรียบง่าย ใช้งานง่ายสำหรับ use case ที่มีเนื้อหาเดียว ไม่ต้องเรียนรู้ syntax เพิ่ม | ไม่สามารถแยกส่วนเนื้อหาหลายส่วนได้ ถ้าต้องการ layout หลายจุดต้องเปลี่ยนไปใช้ named slots |
Fallback content ใน <slot> | ให้เอกสารในตัวและ UI ที่ไม่ว่างเปล่าเมื่อไม่มีลูกถูกฉายเข้ามา | เพิ่ม markup เล็กน้อยในทุก <slot> และต้องดูแลให้ตรงกับ design จริง |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- คิดว่าเนื้อหาที่ฉายเข้า slot ถูกย้ายออกจาก light DOM — จริง ๆ node ยังอยู่ใน light DOM เดิม มีแค่ตำแหน่ง render เท่านั้นที่เปลี่ยน การ query ด้วย
document.querySelectorยังคืนค่า node เดิม - ลืมว่า fallback content แสดงเฉพาะตอนไม่มีลูกถูกฉายเลย — ถ้ามีลูกแม้แต่ node เดียวถูกฉายเข้ามา fallback จะถูกซ่อนทั้งหมด ไม่ใช่แสดงร่วมกัน
- พยายามสไตล์เนื้อหาที่ถูกฉายเข้า slot ทั้งหมดจาก shadow root ด้วย
::slotted()แบบลึก —::slotted()เลือกได้เฉพาะ top-level element ที่ถูกฉายเข้ามาเท่านั้น ไม่สามารถเลือก descendant ของตัวเองได้
💡 ตัวอย่างจากของจริง
Lit ใช้ default slot เป็นแพทเทิร์นพื้นฐานสำหรับ content projection ในคอมโพเนนต์ที่มีเนื้อหาลูกแบบอิสระ เช่น wrapper หรือ container component
Shoelace ใช้ default slot ร่วมกับ named slot ในคอมโพเนนต์อย่าง
<sl-card>เพื่อให้เนื้อหาหลักตกลงไปอยู่ใน default slot ขณะที่ header/footer ใช้ named slot แยกต่างหาก