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).