Skip to main content

SF-9011 · Concept · Medium

What are slots in LWC and how do you use named and scoped slots?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

A slot is a placeholder a child component declares so a parent can pour markup into it. It’s how LWC composes components without the child knowing exactly what content it will receive — the same Web Components <slot> element you’d use in vanilla DOM.

The default slot

<!-- card.html (child) -->
<template>
    <div class="card">
        <header>{title}</header>
        <div class="body">
            <slot></slot>   <!-- default slot -->
        </div>
    </div>
</template>
<!-- usage.html (parent) -->
<template>
    <c-card title="Account Details">
        <p>Anything I put here ends up in the default slot.</p>
        <lightning-button label="Edit"></lightning-button>
    </c-card>
</template>

The child renders its frame; the parent provides the content. The child has no idea what’s coming.

Named slots

When a card needs a header, body, and footer, declare multiple slots and name them:

<!-- panel.html -->
<template>
    <section class="panel">
        <header><slot name="header"></slot></header>
        <main><slot></slot></main>                  <!-- default -->
        <footer><slot name="footer"></slot></footer>
    </section>
</template>
<!-- usage.html -->
<template>
    <c-panel>
        <h2 slot="header">Open Cases</h2>
        <ul>
            <li>Case #1234</li>
            <li>Case #1235</li>
        </ul>
        <lightning-button slot="footer" label="View all"></lightning-button>
    </c-panel>
</template>

The parent uses the standard HTML slot="name" attribute. Anything without a slot attribute lands in the default (unnamed) slot.

Fallback content

You can give a slot default content that renders only when the parent provides nothing:

<slot name="footer">
    <small>No actions configured.</small>
</slot>

Useful for empty states and progressive enhancement.

Detecting slot content

Sometimes the child needs to know whether a slot was filled — to add a divider, change layout, or skip a wrapper. Use the slotchange event:

<template>
    <slot name="footer" onslotchange={handleFooterChange}></slot>
</template>
handleFooterChange(event) {
    const slot = event.target;
    const assigned = slot.assignedNodes({ flatten: true });
    this.hasFooter = assigned.length > 0;
}

Scoped slots (light DOM only)

A scoped slot lets the child pass data down into the parent’s slot template. Think list components that own iteration but let the parent control row rendering:

<!-- list.html (child, with light DOM) -->
<template lwc:render-mode="light">
    <template for:each={rows} for:item="row">
        <slot lwc:slot-bind={row} key={row.id} name="row"></slot>
    </template>
</template>
<!-- usage.html (parent) -->
<template>
    <c-list rows={contacts}>
        <template lwc:slot-data="row" slot="row">
            <strong>{row.Name}</strong> &mdash; {row.Email}
        </template>
    </c-list>
</template>

Two important constraints:

  • Scoped slots only work in light DOM (lwc:render-mode="light").
  • The parent declares the binding name with lwc:slot-data="row"; that’s the variable the parent’s slot template uses.

Shadow DOM and slot styling

Slotted content lives in the parent’s DOM tree, not the child’s. That has two consequences:

  1. CSS in the child cannot directly style slotted content — except via the ::slotted() selector, which is itself limited to direct children:

    /* Inside card.css */
    ::slotted(*)      { margin: 0.5rem 0; }
    ::slotted(button) { padding: 0.25rem 0.75rem; }
  2. Slotted content uses the parent’s styles, not the child’s. That’s a feature, not a bug — it keeps shadow encapsulation clean.

Common interview follow-ups

  • “How is <slot> different from @api?”@api passes structured data (props); <slot> passes markup. Use props for data, slots for layout flexibility.
  • “What’s lwc:render-mode='light'?” — opts the component out of Shadow DOM. Slotted content is then a full DOM citizen — important for SEO, third-party libraries, and scoped slots.
  • “Why doesn’t my CSS reach into the slot?” — Shadow DOM isolation. Either use ::slotted(), switch to light DOM, or expose CSS custom properties for the parent to set.

When to use slots vs props

You want to pass…Use
A string, number, or data object@api property
Layout / markup the child should host<slot>
A list of items the child should iterateproperty + <slot> for each row template (scoped slot)
A callback functionevent (don’t pass functions as props in LWC)

Verified against: LWC Developer Guide — Pass Markup into Slots. Last reviewed 2026-05-17 for Spring ‘26 release.