Skip to content

Named Slots

A named slot is a <slot> element with a name attribute in the shadow tree, paired with a slot attribute on a light-DOM child. The browser matches them by name and renders each light-DOM child at its corresponding insertion point. Using multiple named slots lets a single component expose several distinct content areas — a common pattern for card, dialog, and layout components.

<my-card>
<span slot="header">Card Title</span>
<p slot="body">Card body text here.</p>
</my-card>
class MyCard extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({ mode: 'open' });
shadow.innerHTML = `
<style>...</style>
<div class="card">
<header><slot name="header">Untitled</slot></header>
<section><slot name="body">No body.</slot></section>
</div>
`;
}
}
customElements.define('my-card', MyCard);

Light-DOM children with a slot attribute that does not match any named slot in the shadow tree are silently skipped — they are not rendered anywhere. This means typos in slot names cause invisible content, so double-check your slot names when debugging missing content.

An element can have both named slots and a default slot at the same time. Named-slot children are distributed to their matching named slots, while any remaining children without a slot attribute fall through to the default slot. This makes it easy to build components that have structured sections (header, footer) plus a freeform content area.

OptionBenefitCost
Multiple named slotsLets consumers compose the layout flexibly — great for multi-part components like cards or dialogsAdds a learning curve — consumers must know the exact slot names, and a typo makes content disappear silently
A single slot name (default slot only)Easy to learn, no chance of a slot-name typoLimits your ability to lay out multiple separate content areas
  • Mistyping a slot attribute so it doesn’t match any named slot in the shadow tree — that content is silently never rendered, with no error at all. Always double-check the names match.
  • Expecting to style every descendant of content projected into a named slot from the shadow root — ::slotted() only selects the top-level projected element, it doesn’t reach into its own descendants.
  • Forgetting fallback content for a named slot that might go unfilled — leaves the UI empty with no explanation when a consumer forgets to fill that slot.

💡 Real-world examples

Shoelace uses named slots extensively in its component API design — like the prefix/suffix slots in <sl-input> or the icon slot in <sl-button> — so consumers can inject icons or extra content flexibly.

Lit recommends the named-slots pattern for building composable components, such as a layout component with separate header, content, and footer slots.

How do you assign a light-DOM child to a named slot called 'header'?
What happens to a light-DOM child whose slot attribute does not match any named slot in the shadow tree?
An element with two named slots — 'header' and 'footer' — and one default slot can accept how many light-DOM children simultaneously?