Default Slot
How the default slot works
Section titled “How the default slot works”A <slot> element with no name attribute is the default slot. All light-DOM children that do not have a slot attribute are distributed there. You place the <slot> inside your shadow root, and the browser takes care of rendering the projected children at that position.
<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
Section titled “Fallback content”Content placed inside the <slot> element itself is the fallback. It renders only when no light-DOM children are projected into that slot. If the consumer provides children, the fallback is hidden; if they provide none, the fallback shows.
This is a zero-cost way to make a component self-documenting: the fallback text describes what the consumer is expected to supply.
Slot projection is not a copy
Section titled “Slot projection is not a copy”The light-DOM child stays in the light DOM — only its rendering position moves to the slot. The node is not cloned or transferred. For example, document.querySelector('my-box').firstChild still returns the <p> element even after it has been projected into the shadow root. Event listeners attached to the light-DOM node continue to work normally.
Trade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
| A single default slot | Simple, easy to use for a single-content use case, no extra syntax to learn | Can’t separate content into multiple areas — switch to named slots if you need multiple layout spots |
Fallback content inside <slot> | Provides built-in documentation and a non-empty UI when no children are projected | Adds a little extra markup to every <slot>, and you have to keep it matching the real design |
Common mistakes
Section titled “Common mistakes”- Thinking content projected into a slot is moved out of the light DOM — the node actually stays in the same light DOM; only its render position changes. Querying with
document.querySelectorstill returns the same node. - Forgetting fallback content only shows when no children are projected at all — if even one child is projected, the fallback is hidden entirely, not shown alongside it.
- Trying to style all slotted content from the shadow root with a deep
::slotted()—::slotted()can only select the top-level projected element, not its descendants.
💡 Real-world examples
Lit uses the default slot as the basic pattern for content projection in components with free-form child content, like a wrapper or container component.
Shoelace combines a default slot with named slots in a component like
<sl-card>, so the main content falls into the default slot while the header/footer use separate named slots.