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

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);

เนื้อหาที่วาง ภายใน <slot> element เองคือ fallback จะ render ก็ต่อเมื่อไม่มีเนื้อหาลูกจาก light DOM ถูกฉายเข้าไปใน slot นั้น หากผู้ใช้งานใส่ลูกเข้ามา fallback จะถูกซ่อน หากไม่ได้ใส่ลูกใด ๆ fallback จะแสดงขึ้นมา

นี่เป็นวิธีที่ไม่มีต้นทุนในการทำให้คอมโพเนนต์อธิบายตัวเองได้ ตัว fallback text จะบอกว่าผู้ใช้งานควรจะใส่อะไรเข้ามา

ลูกใน light DOM ยังคงอยู่ใน light DOM มีเพียง ตำแหน่งการ render เท่านั้นที่ย้ายไปอยู่ที่ slot ตัว node ไม่ได้ถูก clone หรือย้ายไปไหน ตัวอย่างเช่น document.querySelector('my-box').firstChild ยังคงคืนค่า <p> element แม้ว่าจะถูกฉายเข้าไปใน shadow root แล้วก็ตาม event listener ที่ผูกไว้กับ node ใน light DOM ก็ยังทำงานได้ตามปกติ

ตัวเลือกBenefitCost
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 แยกต่างหาก

ลูกใน light DOM แบบไหนที่ถูกฉายเข้า default slot?
fallback content ภายใน `<slot>` render เมื่อใด?
หลังการฉายเข้า slot แล้ว node ลูกใน light DOM อยู่ที่ไหนใน DOM?