DEV Community

Cover image for Slot Composition in Lit - What it is and how it is used
Nick Alico
Nick Alico

Posted on

Slot Composition in Lit - What it is and how it is used

Slotting, or slotted composition, is one of those technical concepts that can be very confusing to initially understand. Its modular rendering between elements can make it difficult for people new to Lit to see the changes they are making and how the updated content is actually rendered.

For this assignment, I have been working on re-engineering a modular card component:

Image of Visual Goal of Cards

In order to make the constuction of this component more modular, it was determined that breaking down the component into smaller elements would be a fantastic way to allow for the dynamic rendering of content, such as the type/theme of the card, header and subheader content, card body content, or any other media you may want to place in a card.

I think the official Lit documentation on slots is a great resource to check out, as I will be covering the content here as well.

At a simple level, you can think of slots somewhat like a modular container that you have complete structural control over. Slotting gives you the ability to pass dynamic content between different elements that you create, while supporting the ability to struture the rendered HTML and content however you see fit! This passage of content allows for abstraction of code in each element so that it is much easier to read and follow where content is being passed.

For example, take a look at the banner code which contains the icon and banner headings of the card:

CardBanner.js

<div id="bannerElement">
    <sci-card-icon
    icon="test"
    my-icon="${this.myIcon}"
    type="${this.myIcon}"
    ></sci-card-icon>
    <div  id="banner">
        <div  id="headers">
            <slot  id="main-header"  name="main-header"></slot>
            <slot  id="sub-header"  name="sub-header"></slot>
        </div>
    </div>
</div>
<script  type="module">
    import './src/app.js';
    import './src/SciCardIcon.js';
</script>
Enter fullscreen mode Exit fullscreen mode

Here, we are defining two slots using the <slot> tag. This example performs slotting using named slots. The custom name use choose will be used as the name that you will use where you want to actually render these headings on the card. If we migrate over to our Card.js file, we will see a <div slot="main-header"> which you should recognize when it was defined from the above <slot name="main-header">.

Card.js

<div
class="slot-wrapper"
data-label="Header"
data-layout-slotname="header"
>
    <sci-card-banner  my-icon="${this.myIcon}"  type="${this.type}">
        <div  slot="main-header">
            <slot  name="mainheader">${this.mainheader}</slot>
        </div>
        <div  slot="sub-header">
            <slot  name="subheader">${this.subheader}</slot>
        </div>
    </sci-card-banner>
</div>
Enter fullscreen mode Exit fullscreen mode

The <div slot=""> is the keyword reference used to tell Lit how we want to structure the rendering and where we want the "main-header" and "sub-header" text to render relative to the icon in the banner. The astute eye will notice that Card.js is using yet another slot tag within the already defined structure of slot=main-header like we discussed. ${this.mainheader} references the actual text we want to render, but Card.js isn't the highest element in our scaffolding that we are rendering. We now see <slot name="mainheader"> encapsulating that header text. One level outside of that, we see the entire outer DIV is labeled as <div data-layout-slotname="header">. Let's go look at the outermost layer of our element tree: CardFrame.js.

CardFrame.js

<div>
    <sci-card  type="${this.type}">
        <div  slot="header"></div>
    </sci-card>
</div>
Enter fullscreen mode Exit fullscreen mode

Here, you can see that in a very clean and modular manner, we are simply specifying that inside our sci-card (Card.js) element, we want to have everything that's rendered inside it to be from the slot with name="header", which directly references the outer DIV in Card.js. Therefore, we can now see that the entire HTML of that specific card banner will be rendered within the <sci-card> tag. This is great for readability, and makes it clear to developers that all they have to do is find where a slot with name="header" is defined in order to see the next layer of slotted content

Please take a look at the official documentation for an even simpler example of using slots.

I hope you learned something useful from this escapade into slots!

Check out the project if you are interested!


Header image provided by: https://i0.hippopx.com/photos/386/749/243/programming-html-code-coding-preview.jpg

Discussion (0)