LWC Slots — Complete Guide: Unnamed, Named & Best Practices

Understand how slots enable content projection in Lightning Web Components (LWC). Learn unnamed and named slots, patterns, code samples, and best practices to build reusable components.

What are slots in LWC?

Slots in Lightning Web Components are placeholders in a child component template that allow parent components to inject (project) content. They enable composition over inheritance and make components flexible and reusable. Slotted content retains the parent’s context and can be used for layouts, cards, modals, and more.

Types of slots

  • Unnamed slots (default) — accept any content without a slot name.
  • Named slots — allow multiple specific content areas identified by name (e.g., header, footer, sidebar).

Unnamed slot example (child)

// cardComponent.js
import { LightningElement } from 'lwc';

export default class CardComponent extends LightningElement {}


<!-- cardComponent.html -->
<template>
    <div class="slds-card">
        <div class="slds-card__header">
            <h2 class="slds-card__header-title">Card Title</h2>
        </div>
        <div class="slds-card__body slds-card__body_inner">
            <!-- Unnamed/Default Slot -->
            <slot></slot>
        </div>
    </div>
</template>

Unnamed slot example (parent)

// parentComponent.js
import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {}


<!-- parentComponent.html -->
<template>
    <c-card-component>
        <p>This content will be projected into the card body!</p>
        <lightning-button label="Click Me"></lightning-button>
    </c-card-component>
</template>

Named slots example

Named slots are useful when your child component exposes multiple content regions (header, body, footer, sidebar).

// modalComponent.js
import { LightningElement, api } from 'lwc';

export default class ModalComponent extends LightningElement {
    @api title = 'Modal Title';
    @api isOpen = false;

    handleClose() {
        this.dispatchEvent(new CustomEvent('close'));
    }
}


<!-- modalComponent.html -->
<template>
    <template if:true={isOpen}>
        <section class="slds-modal slds-fade-in-open">
            <div class="slds-modal__container">
                <!-- Header Slot -->
                <header class="slds-modal__header">
                    <slot name="header">
                        <h2 class="slds-modal__title">{title}</h2>
                    </slot>
                    <button class="slds-button slds-button_icon slds-modal__close" onclick={handleClose}>
                        <lightning-icon icon-name="utility:close" size="small"></lightning-icon>
                    </button>
                </header>

                <div class="slds-modal__content slds-p-around_medium">
                    <slot></slot>
                </div>

                <footer class="slds-modal__footer">
                    <slot name="footer">
                        <lightning-button label="Close" onclick={handleClose}></lightning-button>
                    </slot>
                </footer>
            </div>
        </section>
        <div class="slds-backdrop slds-backdrop_open"></div>
    </template>
</template>

Complete working layout example

Use layout components to provide header, sidebar, main, and footer regions via named and default slots.

// layoutComponent.js
import { LightningElement, api } from 'lwc';

export default class LayoutComponent extends LightningElement {
    @api title = 'Page Title';
    @api showSidebar = true;
}


<!-- layoutComponent.html -->
<template>
    <div class="page-container">
        <header class="page-header slds-p-around_medium">
            <slot name="header">
                <h1>{title}</h1>
            </slot>
        </header>

        <div class="page-content slds-grid">
            <aside if:true={showSidebar} class="sidebar slds-col slds-size_1-of-4">
                <slot name="sidebar">
                    <div class="slds-box">
                        <p>Default Sidebar Content</p>
                    </div>
                </slot>
            </aside>

            <main class="main-content slds-col slds-size_3-of-4">
                <slot></slot>
            </main>
        </div>

        <footer class="page-footer slds-p-around_medium">
            <slot name="footer">
                <p>&copy; 2025 Default Footer</p>
            </slot>
        </footer>
    </div>
</template>

Slot features & best practices

  • Provide default content for optional slots so the component degrades gracefully.
  • Use named slots for clearly defined areas (header, footer, sidebar).
  • Keep slot names descriptive and avoid excessive slots to reduce complexity.
  • Don’t rely on slot content for internal component logic; instead, expose proper @api properties or events.
  • Access slotted content safely using the slot element and assignedElements()/assignedNodes() in JavaScript when needed.

Accessing slotted content (JS)

get hasHeaderSlot() {
    const slot = this.template.querySelector('slot[name="header"]');
    return slot && slot.assignedElements().length > 0;
}

Common use cases

  • Layout components (headers, sidebars, footers)
  • Card components (title, body, actions)
  • Modal/dialog components (header, body, footer)
  • List/table components (custom row templates)
  • Form components (dynamic field layouts)

Why this matters

Slots make LWC components composable, reusable, and easier to maintain. They help separate structure from content so teams can create generic, configurable building blocks for Salesforce UIs.

Key takeaways

  • Use slots for content projection and composition.
  • Favor named slots for multiple defined regions and provide defaults for optional slots.
  • Handle empty slots and avoid coupling component logic to slotted content.

For Salesforce admins, developers, and product owners: adopting slot-based component patterns reduces duplication, speeds UI composition, and improves maintainability across your org’s Lightning apps.