Skip to content

Lit Slots

Slots let a Lit component accept and display markup provided by whoever uses it, similar to a function parameter for content. This lesson covers the default (unnamed) <slot>.

What a Slot Does

A <slot> element inside your component's template acts as a placeholder: any light DOM children the consumer places inside your custom element's tags get 'projected' into that slot's position in the Shadow DOM, visually appearing there while remaining, structurally, children of the original light DOM tree.

This is the standard Web Components mechanism for content projection (similar to React's children prop or Vue's default slot), and Lit doesn't add anything special on top — you use the native <slot> element directly inside an html template.

class FancyCard extends LitElement {
  static styles = css`
    .card { border: 1px solid #ddd; border-radius: 8px; padding: 1rem; }
  `;

  render() {
    return html`
      <div class="card">
        <slot></slot>
      </div>
    `;
  }
}

// Usage:
// <fancy-card><p>Any markup goes here.</p></fancy-card>

The <p> element written by the consumer is projected into the <slot> position, appearing visually inside .card while remaining a light DOM child of <fancy-card>.

Default Slot Syntax

render() {
  return html`<slot></slot>`;
}

// Fallback content shown only if the consumer provides none:
render() {
  return html`<slot>Default content</slot>`;
}
  • A component can have at most one default (unnamed) <slot> — additional slots must be named (covered in the next lesson).
  • Content placed between a <slot>'s own tags is fallback content, shown only when the consumer provides nothing to project.
  • Slotted content keeps its original light DOM styling context, not the component's Shadow DOM styles, unless targeted with ::slotted().
  • Multiple light DOM children are all projected together into the same default slot, in their original order.

Slots Quick Reference

Core vocabulary for content projection.

Term Meaning
Light DOM The regular DOM tree the consumer writes, outside your Shadow DOM
Shadow DOM Your component's own encapsulated internal DOM tree
<slot> A placeholder in Shadow DOM where light DOM content is projected
Fallback content Content inside <slot>...</slot> shown only if nothing is projected
::slotted() CSS selector for styling projected content from inside Shadow DOM
slotchange event Fires when the projected content in a slot changes

Styling Slotted Content with ::slotted()

Because your component's static styles are scoped to its own Shadow DOM, they normally don't apply to slotted light DOM content. The ::slotted() pseudo-element selector is the one exception, letting you apply limited styling (mostly layout-related properties, not deep descendant selectors) to top-level projected elements.

static styles = css`
  ::slotted(p) {
    margin: 0;
    color: #333;
  }
`;

::slotted() can only target elements directly projected into the slot, not their descendants — e.g. ::slotted(p) span won't work.

Providing Fallback Content

Fallback content is useful for components that should still display something reasonable if the consumer forgets to provide content, such as a placeholder message or icon.

render() {
  return html`
    <div class="empty-state">
      <slot>No content provided.</slot>
    </div>
  `;
}

// <fancy-card></fancy-card> displays "No content provided."
// <fancy-card><p>Hi</p></fancy-card> displays "Hi" instead

Common Mistakes

  • Trying to deeply style slotted content's descendants with ::slotted(), which only reaches the top-level projected elements.
  • Forgetting that slotted content remains part of the light DOM, so page-level (not component) stylesheets still apply to it by default.
  • Placing more than one unnamed <slot> in a template and being confused about which one receives the projected content (only the first is used meaningfully).
  • Assuming slotted elements are 'moved' into the Shadow DOM — they are visually projected there but remain structurally in the light DOM tree.

Key Takeaways

  • <slot> projects a consumer's light DOM content into a specific position in your Shadow DOM template.
  • Fallback content inside <slot>...</slot> displays only when nothing is projected.
  • ::slotted() is the limited CSS mechanism for styling top-level projected elements from inside Shadow DOM.
  • Projected content remains structurally part of the light DOM even though it visually appears inside your component.

Pro Tip

When designing a component meant to wrap arbitrary consumer content (a card, a modal, a layout container), reach for a default <slot> first — it's the Web Components equivalent of accepting children, and keeps your component flexible without needing to know what markup a consumer will pass in.