Web Components are easier than you think

When I went to conferences and saw presentations on the topic of web components, I always thought that it was not only elegant, but also quite difficult. Thousand lines of JavaScript to store just 4 lines of HTML. The speaker either inevitably hid a huge amount of JS code behind simple things, or dived into complex details, then my eyes began to close with boredom, and I began to think about whether my daily allowance covered the cost of snacks.





However, on a recent project made to learn HTML easily (of course, by adding zombies and silly jokes), I decided that it was necessary to describe every HTML element in the spec. Apart from that conference, I first started with the introduction <slot>



and <template>



the elements, and when I wanted to write something interesting about them in the project, I had to delve into the subject.





And as I went deeper, I realized that Web Components are easier than I thought.





Either web components have come a long way since I dreamed of snacking at a conference, or I let my initial fear get in the way of really getting to know them, or maybe both.





I'm here to tell you yes, you can create a web component. Let's put fear and even snacks outside the door to get things done together.





Let's start with a <template>

<template>



is an HTML element that allows us to create a template (HTML structure for web components).





The code
<template>
  <p>The Zombies are coming!</p>
</template>
      
      



The element <template>



is very important because it allows you to keep everything together. It is like a base for your home, a base from which everything that we call a finished building begins to build. Let's use this little snippet of code for our <apocalyptic-warning>



component that notifies us about the coming of the zombie apocalypse.





Then there is the <slot> component

<slot>



is just an HTML element, like <template>



. But in our case, it <slot>



configures what it <template>



displays on the page.





The code
<template>
  <p>The <slot>Zombies</slot> are coming!</p>
</template>
      
      



"Zombies" ( ?) <template>



. , . "Zombies".





<slot>



placeholder



. placeholder



, , - placeholder



. - name



.





<template>
  <p>The <slot name="whats-coming">Zombies</slot> are coming!</p>
</template>
      
      



name



- , <template>



. "whats-coming" . , -, <slot>



, - , , .





-

, , ( : JS , ).





<apocalyptic-warning>
  <span slot="whats-coming">Halitosis Laden Undead Minions</span>
</apocalyptic-warning>

<template>
  <p>The <slot name="whats-coming">Zombies</slot> are coming!</p>
</template>
      
      



, ? <apocalyptic-warning>



, HTML . <span>



"whats-coming". <span>



"Zombies", .





, - , HTML , . , , -.





? , ? , . , <slot>



, JavaScript.





, JavaScript , , , , . , , .





-, -. : , .





, .





//   -   

customElements.define("apocalyptic-warning", class extends HTMLElement {
  	  //  ,          HTML 
  
  	//   ,    
    constructor() {

      //   , .   HTMLElement.      HTML .
      super();

      //  <template>      `warinng`
      let warning = document.getElementById("warningtemplate");
      
      //      `mywarning`
      let mywarning = warning.content;

      const shadowRoot = this.attachShadow({mode: "open"}).appendChild(mywarning.cloneNode(true));
    }
});
      
      



, .





const shadowRoot = this.attachShadow({mode: "open"}).appendChild(mywarning.cloneNode(true));
      
      



. -, - (this) , Shadow DOM.{ mode: open }



, JavaScript :root



Shadow DOM , - . Shadow DOM ( : HTML Node). , . , Shadow DOM , <slot>



slot , .





. -, , .





JS:





customElements.define('apocalyptic-warning',
    class extends HTMLElement {
      constructor() {
        super();
        let warning = document.getElementById('warningtemplate');
        let mywarning = warning.content;
        
         const shadowRoot = this.attachShadow({mode: 'open'}).appendChild(mywarning.cloneNode(true));
        
      }
    });
      
      



HTML:





<p>The Apocalypse will never happen!</p>
<apocalyptic-warning>
   <span slot="whats-coming">Undead</span>
</apocalyptic-warning>
<apocalyptic-warning>
   <span slot="whats-coming">Halitosis Laden Zombie Minions</span>
</apocalyptic-warning>
<template id="warningtemplate">
  <style>
    p {
      background-color: pink;
      padding: 0.5em;
      border: 1px solid red;
    }
  </style>
    <p>The <slot name="whats-coming">Zombies</slot> are coming!</p>
</template>
      
      



: Codepen





, . , CSS. , <style>



<template>



.





<template id="warningtemplate">
  <style>
    p {
      background-color: pink;
      padding: 0.5em;
      border: 1px solid red;
    }
  </style>

    <p>The <slot name="whats-coming">Zombies</slot> are coming!</p>
</template>
      
      



, , Shadow DOM.





, , , , , Shadow DOM. , Shadow DOM DOM , . - , DOM .





, , <style>,



<slot>



. , . - , CSS , , . , -, CSS.





apocalyptic-warning span {
  color: blue;
}
      
      



, CSS <template>



.





JavaScript , , , , <zombie-profile>.







customElements.define("zombie-profile",
  class extends HTMLElement {
    constructor() {
      super();
      let profile = document.getElementById("zprofiletemplate");
      let myprofile = profile.content;
      const shadowRoot = this.attachShadow({mode: "open"}).appendChild(myprofile.cloneNode(true));
    }
  }
);
      
      



HTML CSS.





<template id="zprofiletemplate">
  <style>
    img {
      width: 100%;
      max-width: 300px;
      height: auto;
      margin: 0 1em 0 0;
    }
    h2 {
      font-size: 3em;
      margin: 0 0 0.25em 0;
      line-height: 0.8;
    }
    h3 {
      margin: 0.5em 0 0 0;
      font-weight: normal;
    }
    .age, .infection-date {
      display: block;
    }
    span {
      line-height: 1.4;
    }
    .label {
      color: #555;
    }
    li, ul {
      display: inline;
      padding: 0;
    }
    li::after {
      content: ', ';
    }
    li:last-child::after {
      content: '';
    }
    li:last-child::before {
      content: ' and ';
    }
  </style>

  <div class="profilepic">
    <slot name="profile-image"><img src="https://assets.codepen.io/1804713/default.png" alt=""></slot>
  </div>

  <div class="info">
    <h2><slot name="zombie-name" part="zname">Zombie Bob</slot></h2>

    <span class="age"><span class="label">Age:</span> <slot name="z-age">37</slot></span>
    <span class="infection-date"><span class="label">Infection Date:</span> <slot name="idate">September 12, 2025</slot></span>

    <div class="interests">
      <span class="label">Interests: </span>
      <slot name="z-interests">
        <ul>
          <li>Long Walks on Beach</li>
          <li>brains</li>
          <li>defeating humanity</li>
        </ul>
      </slot>
    </div>

    <span class="z-statement"><span class="label">Apocalyptic Statement: </span> <slot name="statement">Moooooooan!</slot></span>

  </div>
</template>
      
      



CSS <zombie-profile>



CSS. , , , <template>



.





zombie-profile {
  width: calc(50% - 1em);
  border: 1px solid red;
  padding: 1em;
  margin-bottom: 2em;
  display: grid;
  grid-template-columns: 2fr 4fr;
  column-gap: 20px;
}
zombie-profile img {
  width: 100%;
  max-width: 300px;
  height: auto;
  margin: 0 1em 0 0;
}
zombie-profile li, zombie-profile ul {
  display: inline;
  padding: 0;
}
zombie-profile li::after {
  content: ', ';
}
zombie-profile li:last-child::after {
  content: '';
}
zombie-profile li:last-child::before {
  content: ' and ';
}
      
      



:





: Codepen





, , , -, . , , - , , .





That's all. What are you more afraid of now: web components or a zombie apocalypse? In the not so distant past, I could have said that web components, but now zombies are the only thing that worries me (Well, and will my daily allowance cover the costs of snacks).








All Articles