Tutorial

Composing Custom Elements With Slots And Named Slots

Published on September 19, 2017
    author

    Alligator.io

    Composing Custom Elements With Slots And Named Slots

    With Shadow DOM, we can create Web Components that are a composition between the component’s internals and elements provided at author-time by the user of the custom element. This is similar with using either option or optgroup elements inside a native select element. This composition is made possible using a mechanism known as slots and here we’ll go over how to use slots and named slots in your custom elements to allow for interesting compositions.

    Your First Slotted Content

    Allowing users of your custom elements to add their own markup and elements as part of your element is as simple as using the slot element in your component’s template.

    Here’s an example of a dumb custom element that only acts as a styled shell for content that’s added when the element is used:

    my-info-box.js
    (function() {
      const template = document.createElement('template');
    
      template.innerHTML = `
        <style>
          :host {
            display: block;
            contain: content;
            text-align: center;
            background: papayawhip;
            max-width: 500px;
            margin: 0 auto;
            box-shadow: 0 0 10px rgba(128, 100, 38, 0.34);
            border-radius: 8px;
            border: 2px dashed #ccc049;
          }
        </style>
    <span class="code-annotation">&#x3C;slot&#x3E;&#x3C;/slot&#x3E;</span>  `;
      class MyInfoBox extends HTMLElement {
        constructor() {
          super();
      this.attachShadow({ mode: 'open' });
      this.shadowRoot.appendChild(template.content.cloneNode(true));
    }  }
    
    

    Wondering about the use of :host for our element’s style? Read about styling custom elements.

    This element can then be used like this:

    <my-info-box>
      <p>I'm slotted content!</p>
    </my-info-box>
    

    The markup added inside a custom element is called the light DOM and it stays outside of the Shadow DOM’s reach, as you can see from this screenshot of the element as seen from Chrome’s DevTools:

    Shadow DOM vs Light DOM

    Elements in the light DOM are instead accessible directly as children of the element, so you could do something like this to grab an element, as you would normally to access an element in the DOM:

    const myInfoBox = document.querySelector('my-info-box');
    const text = myInfoBox.children[0].innerText;
    
    console.log(text); // I'm slotted content!
    

    A light DOM element that’s being used in a slot is known as a distributed node.

    Default Content

    You can provide default content for a slot, in case none is provided when the element is used:

    my-info-box.js (partial)
    <slot>
     <p>I'm some default content!</p>
    </slot>
    

    And this default content will be used if the element is used like this:

    <my-info-box></my-info-box>
    

    Named Slots

    Creating more complex elements that can take various pieces of content from the element’s user can be done easily using named slots. You can see a simple example here where a named slot is used alongside a regular slot:

    my-info-box.js (partial)
    <div>
      <slot name="title"></slot>
      <hr>
      <slot></slot>
    </div>
    

    The element can then be used like this:

    <my-info-box>
      <span slot="title">🍭 Fancy title</span>
      <p>I'm going straight to the anonymous slot.</p>
    </my-info-box>
    

    Thanks to named slots, you can easily create a complex custom elements that compose multiple pieces together. For example, a nav bar that takes a title, a logo, left navigation items and right navigation items.

    Styling Slotted Content With ::slotted

    We can style slotted content using the ::slotted() selector. Here’s a very simple example:

    <style>
      ::slotted(span) {
        background: pink;
      }
      ::slotted(.content) {
        font-family: monospace;
      }
    </style>
    
    <div>
      <slot name="title"></slot>
      <hr>
      <slot></slot>
    </div>
    

    And, with this, the title in the following example will have a pink background and the main content will be in a monospace font:

    <my-info-box>
      <span slot="title">🍭 Fancy title</span>
      <p class="content">I'm going straight to the anonymous slot.</p>
    </my-info-box>
    

    Note that the selector used with ::slotted should select a top-level element, as it can’t match a slot using a nested element.

    Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

    Learn more about our products

    About the authors
    Default avatar
    Alligator.io

    author

    While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

    Still looking for an answer?

    Ask a questionSearch for more help

    Was this helpful?
     
    Leave a comment
    

    This textbox defaults to using Markdown to format your answer.

    You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

    Try DigitalOcean for free

    Click below to sign up and get $200 of credit to try our products over 60 days!

    Sign up

    Join the Tech Talk
    Success! Thank you! Please check your email for further details.

    Please complete your information!

    Featured on Community

    Get our biweekly newsletter

    Sign up for Infrastructure as a Newsletter.

    Hollie's Hub for Good

    Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

    Become a contributor

    Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

    Welcome to the developer cloud

    DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

    Learn more