Álvaro José Agámez Licha
Software Developer
https://github.com/aagamezl
@aagamezl
Web Components is a suite of different technologies allowing you to create reusable custom elements (with their functionality encapsulated away from the rest of your code) and utilize them in your web apps.
Web components are based on existing web standards. Features to support web components are currently being added to the HTML and DOM specs, letting web developers easily extend HTML with new elements with encapsulated styling and custom behavior.
Web components are based on four main specifications:
The Custom Elements specification lays the foundation for designing and using new types of DOM elements.
class MyComponent extends HTMLElement {
connectedCallback() {
this.innerHTML = `<h1>Hello world</h1>`;
}
}
customElements.define('my-component', MyComponent);
<my-component></my-component>
The shadow DOM specification defines how to use encapsulated style and markup in web components.
let shadow = elementRef.attachShadow({mode: 'open'});
let shadow = elementRef.attachShadow({mode: 'closed'});
let myShadowDom = myCustomElem.shadowRoot;
Open means that you can access the shadow DOM using JavaScript written in the main page context. If you attach a shadow root to a custom element with mode: closed set, you won't be able to access the shadow DOM from the outside.
The ES Modules specification defines the inclusion and reuse of JS documents in a standards based, modular, performant way.
The HTML template element specification defines how to declare fragments of markup that go unused at page load, but can be instantiated later on at runtime.
<template id="book-template">
<li>
<span class="title"></span> —
<span class="author"></span>
</li>
</template>
<ul id="books"></ul>
const fragment = document.getElementById('book-template');
const books = [
{ title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },
{ title: 'A Farewell to Arms', author: 'Ernest Hemingway' },
{ title: 'Catch 22', author: 'Joseph Heller' }
];
books.forEach(book => {
// Create an instance of the template content
const instance = document.importNode(fragment.content, true);
// Add relevant content to the template
instance.querySelector('.title').innerHTML = book.title;
instance.querySelector('.author').innerHTML = book.author;
// Append the instance ot the DOM
document.getElementById('books').appendChild(instance);
});
The basic approach for implementing a web component generally looks something like this:
A custom element can define special lifecycle hooks for running code during interesting times of its existence. These are called custom element reactions.
class AppDrawer extends HTMLElement {
constructor() {
// always call super() first in the constructor.
super();
...
}
static get observedAttributes() { return ['c', 'l']; }
connectedCallback() {
...
}
disconnectedCallback() {
...
}
attributeChangedCallback(attrName, oldVal, newVal) {
...
}
}
constructor: An instance of the element is created or upgraded. Useful for initializing state, settings up event listeners, or creating shadow dom. See the spec for restrictions on what you can do in the constructor.
connectedCallback: Called every time the element is inserted into the DOM. Useful for running setup code, such as fetching resources or rendering. Generally, you should try to delay work until this time.
disconnectedCallback: Called every time the element is removed from the DOM. Useful for running clean up code.
attributeChangedCallback(attrName, oldVal, newVal): Called when an observed attribute has been added, removed, updated, or replaced. Also called for initial values when an element is created by the parser, or upgraded. Note: only attributes listed in the observedAttributes property will receive this callback.
adoptedCallback(): The custom element has been moved into a new document (e.g. someone called document.adoptNode(el)).
class AppDrawer extends HTMLElement {
constructor() {
// always call super() first in the constructor.
super();
...
}
connectedCallback() {
...
}
disconnectedCallback() {
...
}
attributeChangedCallback(attrName, oldVal, newVal) {
...
}
}