Slotted content page

Use slot elements to allow more control over non-critical parts of your component.

Overview

In this part we will:

  • Use slot elements to allow customization.

Problem

In the previous section we allowed the header to be styled with a few CSS properties. We could continue to add more custom properties so even more of the header could be customized. For example, we could allow the user of our component to change the heading text by providing an attribute like title="My Bus Tracker".

An easier way to allow consumers of your component to have complete control is to use slots. In this part we want to allow the header to be replaced with a custom header. In the end it should look like:

Header customized using slots.

How to Solve This Problem

  1. Provide a slot for the custom header passed to bus-tracker.
  2. Use named slots to allow the header slot to be provided by the user.
  3. Add custom styles to style the new header.

Technical requirements

Use this markup as the header that is passed into the component:

<header>
  <h1>My Bus Tracker!</h1>
</header>

And use this CSS to style the header:

background: crimson;
color: wheat;
text-align: center;

What you need to know

  • How the slot element works.
  • How to give slots names to allow multiple slotted content.

Slots

The slot has a curious effect when used within shadow DOM. It will take DOM within the custom element’s children and inject (but not move) those nodes as children of itself.

Default content can be specified by nesting DOM inside of the <slot> element.

<template>
  <slot>This is using <strong>default</strong> content.</slot>
</template>

<div id="one"></div>
<div id="two">
  This is using slotted content.
</div>

<script type="module">
let template = document.querySelector('template');

let one = document.querySelector('#one');
one.attachShadow({ mode: 'open' });
one.shadowRoot.append(document.importNode(template.content, true));

let two = document.querySelector('#two');
two.attachShadow({ mode: 'open' });
two.shadowRoot.append(document.importNode(template.content, true));

document.body.append(one, two);
</script>

Named slots

Named slots are used when you want to take some of the children content, but not all of it. This is useful when you have multiple things to be customized. It works like <slot name="header">, with the children needing to add a slot attribute. <header slot="header">.

<div class="my-thing">
  <header slot="header">
    <h1>My Header</h1>
  </header>
</div>

<template>
  <slot name="header">
    <header>Default Header</header>
  </slot>
</template>

<script type="module">
let el = document.querySelector('.my-thing');
el.attachShadow({ mode: 'open' });

let template = document.querySelector('template');
let frag = document.importNode(template.content, true);

el.shadowRoot.append(frag);
</script>

Solution

✏️ Wrap the <header> within the bus-tracker component with a <slot name="header">. This will completely replace the header if a child element provides the slot="header" attribute value.

Click to see the solution

    --header-background: salmon;
    --header-text-transform: capitalize;
  }
  header[slot=header] {
    background: crimson;
    color: wheat;
    text-align: center;
  }
</style>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyD7POAQA-i16Vws48h4yRFVGBZzIExOAJI"></script>

<bus-tracker>
  <header slot="header">
    <h1>My Bus Tracker!</h1>
  </header>
</bus-tracker>

<template id="bt-template">
    }
  </style>
  <div class="top">
    <slot name="header">
      <header>
        <h1>Chicago CTA Bus Tracker</h1>
        <p id="loading-routes">Loading routes…</p>
      </header>
    </slot>

    <ul class="routes-list"></ul>
  </div>

Previous Lesson: Customize header stylesNext Lesson: Dispatching events