Web Components Are Easier Than You Think

By John Rhea

Translation: Chi Ling student

preface

I went to a tech conference and saw some big names demonstrate Web Components, which was pretty nice, but seemed a bit too complicated — HTML code with almost a thousand lines of JavaScript code for single-digit lines. Inevitably, the big guys will gloss over the fact that Web Components require a lot of JavaScript code to work, or dive into seemingly insignificant details. At this point my eyes start to glaze over and I start to stare.

But in a recent reference project, in order to make learning HTML easier, I, a perfectionist, decided that I had to cover every HTML tag in the specification. This is the first time I’ve introduced

and

In the process, I’ve learned a few things — Web Components aren’t as complex as we remember.

Web Components has come a long way since my last daze at tech Talk, and perhaps my initial fear of it prevented me from learning more about it (or was it both daze and fear?). .

I’ll use this article to tell you: Yes, you can create a Web Component!

Don’t be dazed, don’t be scared, try it now.

from<template>start

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

The

Then there is<slot>


, like

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

Here we add the word “Zombies” to the

tag of the HTML template. If nothing is done to the

tag, the contents of the

tag are displayed by default. In this example the word “Zombies” will be displayed by default.


Using the

tag is more like a placeholder, and we can either use the placeholder directly or define something else to replace it, usually using the name attribute to implement the ability to exact substitution.

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

The name attribute tells the Web Component what should go where in the template. Now there’s a

tag with the name whats-coming. In addition to “Zombies”, the

part of the tag has the flexibility to place other content. Assuming “Zombies” is the highest level of warning, it can also be replaced with “Robots”, “Werewolves”, or even “Web Components”.

Use the Web Component

Technically, we’ve already written the Web Component, and we can put it anywhere we want.

<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>
Copy the code

In this case, the < apocalyptic-Warning > Web Component is put on the page just like any other HTML tag. But it also places a tag in the middle, which references the name attribute of the

tag. The content in this
tag is what replaces “Zombies” when the component is rendered.

It is important to note that custom tags must be hyphenated in their names to prevent collisions with new HTML published tags.

There is still some work to be done to get

to be replaced, and it is time to write the JavaScript code.

Registered Web Component

As I said, it does take some JavaScript code to make the above code work, but it’s not as complicated as I thought it would be — thousands of lines of JavaScript, deep into detail. Hopefully I can convince you to learn Web Components with this JavaScript code as well.

You need a constructor to register the custom tag; if you don’t register it, the Web Component is as still and lifeless as a stone statue.

This is the constructor you will use:

// Define the custom tag with an appropriate name in this case 
      
customElements.define(
  'apocalyptic-warning'.// Make sure that this custom tag has all the default attributes and methods of the built-in HTML tag (HTMLElement inherited)
  class extends HTMLElement {
    The constructor is called when a new custom tag is created
    constructor() {
      // Calling the parent constructor, the HTMLElement constructor, is guaranteed to behave exactly the same as creating the built-in HTML tag
      super(a);// Get 
      
      const warning = document.getElementById('warningtemplate');

      // Get the contents of warning and save it in myWarning
      const mywarning = warning.content;

      const shadowRoot = this.attachShadow({mode: 'open'}).appendChild(
        mywarning.cloneNode(true)); }});Copy the code

I left detailed comments on every line of the code above, except the last:

const shadowRoot = this.attachShadow({mode: 'open'}).appendChild(
  mywarning.cloneNode(true));Copy the code

This line of code does a number of things: first, use the custom tag and create a Shadow DOM, {mode: ‘open’} means that JavaScript code outside root can access and manipulate the Shadow DOM, which can be interpreted as a backdoor to the Web Component.

Here you create a Shadow DOM and add a node to it that is a deep copy of the previous HTML template, including all the tags and text content of the template. After the template is added to the Shadow DOM of the custom tag, the

position is taken over by the content matching the name attribute.

Now let’s look at the effect of placing two instances of the same component and changing just one tag to render different content.

Demo (due to mining restrictions, can only jump to Codepen view)

Add styles to the Web Component

As you may have noticed in the Demo, we definitely have the ability to style Web Components using CSS. We can actually include a

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

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

As such, due to the Shadow DOM, styles are applied directly to the current Web Component without global style contamination.

Now, in my mind’s eye, I think of the custom tag as a copy of

Technically, the inserted content is outside of

apocalyptic-warning span {
  color: blue;
}
Copy the code

Demo (due to mining restrictions, can only jump to Codepen view)

But beware! Styles in CSS files do not have access to tags in

Put them together

Let’s take a look at an example of creating a zombie profile card, just like the profile you might need after a zombie apocalypse. To be able to style the default content and anything inserted into it, we need both the

Now the JavaScript code is exactly the same, except that we use the Web Component name

.

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

Here is the HTML template, including the wrapped 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.25 em 0;
      line-height: 0.8;
    }
    h3 {
      margin: 0.5 em 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>
Copy the code

This is the CSS style set for the

tag and its descendants in our main CSS file. Note the repetitions here, which are used to make sure that the replaced tag has the same style as the tag in the 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 ';
}
Copy the code

It’s all in one now!

Demo (due to mining restrictions, can only jump to Codepen view)

There are still a few questions and other nuances, but I hope you now know Web Components better and are more comfortable with it than you were a few minutes ago. Just like we did here, try it out. Perhaps you can add custom Components everywhere in your work to get the feel and meaning of Web Components.

What are you more afraid of now? Web Components or zombie Apocalypse? A few minutes ago I would have said I was more afraid of Web Components, but now I’m proud to say that the zombie apocalypse is the only thing I’m worried about.

Other tutorials worth following: Ruan Yifeng: Getting Started with Web Components