Skip to content

Slots

Components receive child content through the slots parameter.

Default Slot

Children without a slot attribute go into slots.default:

typescript
defineComponent("my-card", (_props, slots) => html`
  <div class="card">
    ${slots.default?.length ? slots.default : html`<p>No content</p>`}
  </div>
`);

html`
  <my-card>
    <h2>Title</h2>
    <p>Body content</p>
  </my-card>
`;

Named Slots

Children with slot="name" go into slots.name:

typescript
defineComponent("my-layout", (_props, slots) => html`
  <div class="layout">
    <header><slot name="header"></slot></header>
    <main><slot></slot></main>
    <footer><slot name="footer"></slot></footer>
  </div>
`);

html`
  <my-layout>
    <h1 slot="header">Page Title</h1>
    <p>Main content</p>
    <small slot="footer">Footer note</small>
  </my-layout>
`;

The slot attribute is automatically removed from rendered output.

Slot Elements

Use <slot> elements in component templates to declare insertion points. Content inside a <slot> element serves as fallback:

typescript
defineComponent("my-card", (_props, slots) => html`
  <div class="card">
    <slot name="header"><h1>Default Title</h1></slot>
    <slot><p>Default body</p></slot>
  </div>
`);

// With no children:
html`<my-card></my-card>`;
// → <div class="card"><h1>Default Title</h1><p>Default body</p></div>

// With matching children:
html`
  <my-card>
    <h2 slot="header">Custom Title</h2>
    <span>Custom body</span>
  </my-card>
`;
// → <div class="card"><h2>Custom Title</h2><span>Custom body</span></div>

Programmatic Access

The slots object is passed directly to the render function:

typescript
defineComponent("my-counter", (_props, slots) => html`
  <span data-testid="count">
    ${slots.default ? slots.default.length : 0} children
  </span>
`);

Whitespace Handling

Text nodes consisting only of whitespace are excluded from slots automatically. Only meaningful element and text nodes are included.