Documentation

Documentation versions (currently viewingVaadin 24)

Dynamically Adding Server-Side Components to Templates

How to add server-side components to templates.

A client-side template can’t render child templates created using the Component or Element API, because it uses the shadow DOM, which renders the shadow tree, instead of the element’s children, which are in the light DOM.

To overcome this, you can add a <slot> element to mark the place where the light DOM elements should be rendered.

Using the <slot> Element

Example: <slot> element in a TypeScript LitElement template.

import { html, LitElement } from 'lit';

class ComponentContainer extends LitElement {
  render() {
    return html`
      <div>
        <slot></slot>
      </div>
    `;
  }
}

customElements.define('component-container', ComponentContainer);

Example: Mapped Java template class.

@Tag("component-container")
@JsModule("./com/example/component-container.ts")
public class ComponentContainer extends LitTemplate {

    public ComponentContainer() {
        Element label = ElementFactory.createLabel("Main layout header");
        Element button = ElementFactory.createButton("Click me");

        getElement().appendChild(label, button);
    }
}
  • Without the <slot> tag in the LitElement template, the label and button would not be visible to the user, even though they can be located in the DOM.

  • You can add multiple components that display in the slot when added to a template element with an open <slot></slot>.

  • You can remove any element from a <slot>. It works as expected and no longer display in the main element.

Using Default Content in the <slot> Element

The <slot> tag can contain default content that’s displayed only if nothing else is set from the light DOM.

Example: <slot> element with default content in a client-side template.

<div style="border: 1px solid black; padding: 10px; margin: 10px;">
    <slot>No components added</slot>
</div>
  • 'No components added' displays initially, and is replaced when at least one child element is added.

Naming Slots

You can name <slot> elements using the name attribute to ensure that only wanted content is added to a particular slot.

Example Using the name attribute in the <slot> element in a client-side template.

<h1><slot name="title"></slot></h1>

<div style="border: 1px solid black; margin: 5px;padding: 5px;">
    <slot>No content given!</slot>
</div>
  • For example, a <label slot="title">Main header</label> element is now not positioned in the default "No content given!" slot, but rather in the <h1><slot name="title">…​ slot.

Nesting Slots

You can also nest named slots inside the main slot.

Example: Nested slot elements in a client-side template.

<slot name="fullName">
    <slot name="firstName"></slot>, <slot name="lastName"></slot>
</slot>
  • The slot shows data for the light DOM <slot="firstName"> and <slot="lastName"> elements, if no <slot="fullName"> element is available. If you add an element to the <slot="fullName"> slot, it overrides and replaces the firstName and lastName data.

Adding Multiple Slots

The default slot and any named slot can contain multiple elements.

Example: Defining multiple elements for the default slot and multiple named slots in a TypeScript LitElement template.

@Tag("name-element")
@JsModule("./com/example/name-element.ts")
public class NameElement extends LitTemplate {
    public NameElement() {
        Element firstName = ElementFactory.createSpan("Jack");
        Element middleName = ElementFactory.createSpan(" James");
        Element surName = ElementFactory.createSpan("Christobald");

        firstName.setAttribute("slot", "firstName");
        middleName.setAttribute("slot", "middleName");
        surName.setAttribute("slot", "lastName");

        getElement().appendChild(firstName, middleName, surName);
    }
}

42936E07-7818-400D-86A1-31991FAEA681