Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
Diagram illustrating the concept of LWC slots for building reusable Salesforce components effectively.
LWC

LWC Slots Guide - Building Reusable Salesforce Components

Tired of building rigid components that break when requirements change? I'll show you how to use LWC slots to create flexible placeholders that make your code much easier to maintain.

The short answer

This guide explains how to use unnamed and named slots in Lightning Web Components to inject markup from parent components into child placeholders. It provides patterns for building flexible, reusable UI layouts without creating excessive @api properties.

Key takeaways Use unnamed slots as default catch-all placeholders to build reusable UI container components. Implement named slots with matching slot attributes to control multi-section layouts such as modals and cards. Check `assignedElements()` on slot elements in JavaScript to conditionally render wrappers and avoid empty whitespace. Include fallback markup inside slot tags to ensure components render gracefully when no content is passed.

If you're tired of building rigid components that break the moment a requirement changes, you need to master LWC slots. Basically, LWC slots are placeholders that let a parent component inject its own markup right into a child component, making your code way more flexible.

I've seen teams struggle with massive components that have twenty different @api properties just to hide or show certain buttons. It's a maintenance nightmare. Instead of hard-coding every possible variation, I use slots to let the parent decide what goes where. It's all about building a shell and letting the consumer fill in the blanks.

Why I always reach for LWC slots

Think of a slot as a "reserved seat" in your component's HTML. The child component defines where the seat is, but the parent component chooses who sits there. This is a massive help when you're trying to build a progress bar or a card that needs to look different depending on whether it's on a dashboard or a record page.

There are two types you'll use: unnamed (default) slots and named slots. An unnamed slot is the catch-all. If the parent passes content without a specific destination, it lands right there. Using unnamed LWC slots is the easiest way to start making your UI primitives reusable.

// cardComponent.html
<template>
  <div class="slds-card">
    <div class="slds-card__header">
      <h2>Standard Card</h2>
    </div>
    <div class="slds-card__body">
      <! - Anything the parent sends will show up here - >
      <slot></slot>
    </div>
  </div>
</template>

A visual diagram of a Salesforce LWC default slot, showing a component container receiving different UI elements into a central placeholder.

A visual diagram of a Salesforce LWC default slot, showing a component container receiving different UI elements into a central placeholder.

Taking control with named LWC slots

Now, here's where it gets interesting. Sometimes a single placeholder isn't enough. If you're building something like a modal, you need specific spots for a header, a body, and a footer. This is where named LWC slots come into play. You just give the slot a name attribute, and the parent targets it using the "slot" attribute on its own elements.

I use this pattern for almost every layout-heavy component I build. It keeps the CSS inside the child component consistent while giving the parent full control over the actual data and actions. It also makes LWC component communication much cleaner because the parent keeps the logic for the buttons it's injecting.

// modalComponent.html
<template>
  <section class="slds-modal slds-fade-in-open">
    <div class="slds-modal__container">
      <header class="slds-modal__header">
        <slot name="header">
          <h2>Default Title</h2>
        </slot>
      </header>
      <div class="slds-modal__content">
        <slot></slot> <! - Default unnamed slot for body - >
      </div>
      <footer class="slds-modal__footer">
        <slot name="footer"></slot>
      </footer>
    </div>
  </section>
</template>

Checking if a slot is empty

One thing that trips people up is trying to hide a wrapper div if no content was passed to a slot. You can't just use an "if:true" on the slot itself. You have to go into the JavaScript and use assignedElements(). I've used this many times to hide a footer section entirely if the parent didn't provide any buttons. It keeps the UI from looking clunky with empty white space.

// modalComponent.js
get hasFooter() {
  const footerSlot = this.template.querySelector('slot[name="footer"]');
  return footerSlot && footerSlot.assignedElements().length > 0;
}

Pro Tip: Always provide default content inside your slot tags. It acts as a fallback so your component doesn't look broken if someone forgets to pass content to it.

Best practices from the field

  • Keep your slot names simple and descriptive like "header", "actions", or "sidebar".
  • Don't go overboard. If you find yourself adding ten slots to one component, you might actually need to break that component down into smaller pieces.
  • Remember that styles in the parent component don't automatically bleed into the child, but the content inside the slot is still technically part of the parent's DOM tree.
  • Use conditional rendering in the child to handle empty slots gracefully so you don't end up with weird margins or borders.

Key Takeaways

  • LWC slots are the best way to handle content projection and build truly reusable UI primitives.
  • Named slots give you multiple injection points for complex layouts like modals or grids.
  • Slotted content stays in the parent's context, which makes event handling and styling much more intuitive.
  • Use assignedElements() in your JS if you need to detect whether a slot actually has content.

So, the next time you're about to add yet another boolean property to a component just to show a specific icon or button, stop. Try using LWC slots instead. It'll make your components much easier to maintain, and your fellow developers will thank you for not making them hunt through a mountain of props just to change a bit of text. Give it a shot on your next project and see how much cleaner your code gets.

Frequently asked questions

What is the difference between named and unnamed slots in LWC?

An unnamed slot acts as a default catch-all that receives any content passed without a target attribute. Named slots use a `name` attribute to map specific markup from the parent to dedicated placeholders in the child component.

How do you check if a slot is empty in LWC?

Query the slot element using `this.template.querySelector` and evaluate `assignedElements().length` in JavaScript. This allows you to conditionally hide surrounding wrapper elements when a parent provides no content.

Why should you use LWC slots instead of @api properties?

Slots allow the parent component to inject custom markup directly into the child, eliminating the need to maintain dozens of `@api` properties for toggling UI elements. This keeps layout styling encapsulated in the child while keeping event handling and logic in the parent.

Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment