<blog-post>
<h2 slot="post-title">#1 Blog Post</h2>
<p slot="post-body">
Lorem ipsum dolor sit amet consectetur,
adipisicing elit.
</p>
</blog-post>
<blog-post>
<h2 slot="post-title">#2 Blog Post</h2>
<p slot="post-body">
Deleniti assumenda architecto aliquid
voluptas eum quam earum quae dolore.
</p>
</blog-post>
class WebComponent extends HTMLElement {
constructor() {
super();
// Re-renders the DOM when state is set to a new value
this._state = new Proxy(this.init(), {
set: (target, property, value) => {
if (!Object.is(target[property], value)) {
target[property] = value;
this.render();
}
return true;
}
});
// Creates the Shadow DOM
this.shadow = this.attachShadow({ mode: "open" });
// Triggers the first render
this.render();
}
set state(obj) {
for (const key in obj) {
this._state[key] = obj[key];
}
}
get state() {
return this._state;
}
render() {
// Bundle styles and html
const templateString = /* HTML */ `
<template>
<style>
${this.styles()}
</style>
${this.html()}
</template>
`;
// Parses the template
const template = new DOMParser()
.parseFromString(templateString, "text/html")
.querySelector("template").content;
// Clears the Shadow DOM
this.shadow.innerHTML = "";
// Attaches a copy of the template to the now empty Shadow DOM
this.shadow.appendChild(template.cloneNode(true));
// Attaches listeners
this.listeners();
}
handle(id, event, handler) {
this.shadow.getElementById(id).addEventListener(event, handler);
}
}
class BlogPost extends WebComponent {
constructor() {
super();
}
init() {
return {
likes: 0
};
}
listeners() {
this.handle("btn-add-like", "click", () => {
this.state.likes = this.state.likes + 1;
});
}
styles() {
return /* CSS */ `
.post-title {
color: red;
}
.post-body {
color: blue;
}
`;
}
html() {
return /* HTML */ `
<article>
<div class="post-title">
<slot name="post-title">[[Post Title]]</slot>
</div>
<div class="post-body">
<slot name="post-body">[[Post Body]]</slot>
<p>Likes: ${this.state.likes}</p>
<button id="btn-add-like">Add +1 Like</button>
</div>
</article>
`;
}
}
customElements.define("blog-post", BlogPost);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.