Skip to main content

How to Compose Salesforce LWCs: HTML Slots vs. Data Properties

In plain words: "Component composition" is just a fancy term for building a large webpage by snapping smaller, reusable pieces (components) together like Lego bricks. In Salesforce LWC, there are two main ways a parent component can give information to a child component: passing raw HTML layout using Slots, or passing actual data values using Properties.

In Salesforce Lightning Web Components (LWC), building reusable user interfaces requires a solid understanding of how components interact. If you want a parent component to control what happens inside a child component, you have to choose the right tool for the job.

Let's explore the two primary methods for composing components—HTML Slots and Data Properties—and look at the code required to implement them.

1. Using HTML Slots for Component Composition

Slots provide a flexible way to compose components by allowing a parent component to inject raw HTML directly into specific areas of a child component's template. Think of a slot as an open window or an empty picture frame waiting to be filled.

Real-Life Example: Standard components like <lightning-card> use slots heavily. The card defines the white box and the border, but it leaves a "slot" open so you can put whatever text, buttons, or images you want inside the body of the card.

Here is how you set up a parent component passing HTML into a child component's slot:

Child Component (childComponent.html):

<template>
  <div class="box">
    <h2>Child Component Header</h2>
    <!-- This slot acts as a placeholder for the parent's HTML -->
    <slot></slot>
  </div>
</template>

Parent Component (parentComponent.html):

<template>
  <div>
    <h1>Parent Component</h1>
    <!-- Calling the child component and passing HTML into its slot -->
    <c-child-component>
      <p>This paragraph will be injected directly into the slot!</p>
    </c-child-component>
  </div>
</template>

When the browser renders this, the final HTML looks like this:

<div>
  <h1>Parent Component</h1>
  <div class="box">
    <h2>Child Component Header</h2>
    <p>This paragraph will be injected directly into the slot!</p>
  </div>
</div>

2. Using Data for Component Composition

Data-based composition relies on JavaScript. Instead of passing HTML tags, the parent component passes variables, text, or objects to the child component via public properties. This is done using the @api decorator in the child component.

This approach is perfect when you want the child component to control its own HTML layout, but rely on the parent for the actual text or logic.

Child Component JavaScript (childComponent.js):

import { LightningElement, api } from 'lwc';

export default class ChildComponent extends LightningElement {
  // @api exposes this property so the parent can set it
  @api message;
}

Child Component HTML (childComponent.html):

<template>
  <div>
    <h2>Child Component</h2>
    <!-- Displaying the data passed from the parent -->
    <p>{message}</p>
  </div>
</template>

Parent Component JavaScript (parentComponent.js):

import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {
  // Define the data to pass down
  greetingMessage = 'Hello from the parent component!';
}

Parent Component HTML (parentComponent.html):

<template>
  <div>
    <h1>Parent Component</h1>
    <!-- Passing the JavaScript variable into the child's exposed property -->
    <c-child-component message={greetingMessage}></c-child-component>
  </div>
</template>
Developer Trap: The Kebab-Case Rule
If you create an @api property in your child component using camelCase (e.g., @api myCustomMessage;), you must pass the data from the parent HTML using kebab-case: <c-child-component my-custom-message={data}>. Trying to use camelCase in the HTML template will fail silently!
360 Card: Slots vs. Data Properties
  • Use Slots When: You want the parent to dictate the layout, UI, and styling. The child acts as an empty container or wrapper (like a modal or a custom card).
  • Use Data Properties When: The child component has a strict layout, but needs dynamic information (like a user's name, a record ID, or a list of accounts to loop through).
Core Takeaway: Slots pass Markup (HTML). Properties pass Logic (Data). Mastering both will allow you to build highly modular and reusable LWC architectures.

Conclusion

Both slots and data-based properties are incredibly powerful techniques for composing Lightning Web Components. Slots give you the flexibility to inject raw HTML into specific areas, while data properties allow a parent to seamlessly pass values and configuration logic down the tree. By understanding the distinct use cases for both, you can ensure your Salesforce codebase remains scalable, reusable, and easy to maintain.

Happy coding!