HTML Custom Elements is another API described as HTML Web components. It allows you to extend HTML by defining new elements, and to tell the browser how to render them.
Basic usage:
customElements.define('my-widget', MyWidget);
This is done using JavaScript and there are some constraints:
The element's new name should have a dash (ex: <my-calendar>, <app-list>, etc.)
The second parameter is a JavaScript class object that defines the behavior of the element. See further examples.
Optionally, a third parameter can be used: a JavaScript object containing an extends property, which specifies the built-in element your element inherits from if any:
customElements.define('my-widget', MyWidget, { extends: 'p' });
"Inheritance" is another aspect of object-oriented programming. If it is new to you, please see earlier reference material.
Here is an example which defines a new element named <my-widget>, that will render as an instance of a template with a shadow DOM:
HTML code for the use of the custom element:
<body>
<my-widget>
<span slot="my-title">Title injected</span>
<span slot="my-paragraph">Paragraph injected</span>
</my-widget>
</body>
Look at lines 2 and 5...
HTML code for the declaration of the template (the same as in one of the previous examples):
<template id="mytemplate">
<style>
h1 {
color:white;
background:red;
}
</style>
<h1>
<slot name="my-title">My default text</slot>
</h1>
<p>
<slot name="my-paragraph">My default text</slot
</p>
</template>
JavaScript code:
// TIP : use "document.currentScript" here to select
// the "local document", the one corresponding to this page.
// this may avoid problems when multiple WebComponents files
// are inserted in the same document. See below...
var localDoc = document.currentScript.ownerDocument;
class MyWidget extends HTMLElement {
constructor() {
super(); // mandatory
const shadowRoot = this.attachShadow({mode: 'open'});
// instanciate template
let t = localDoc.querySelector('#mytemplate');
// add it to the shadow DOM
shadowRoot.appendChild(document.importNode(t.content, true));
}
}
try {
// Define the custom element to the browser
customElements.define('my-widget', MyWidget);
console.log("Element defined");
} catch (error) {
console.log(error);
}
Line 5: we use this particular selector for safety. It means "select the element only in the HTML of the document that is attached to this JavaScript. Web Components might be included in other HTML pages, as we will see in the next pages of this course. A good practice is to select elements only in the HTML page of the Web Component, not in the document that will import the Web Component.
Line 7: definition of the Web Component class attached to the custom element <my-widget>
Lines 8-17: the constructor definition for the class always starts by calling super() so that the correct prototype chain is established. Inside the constructor, we define all the functionality the element will have. Very often this starts by cloning a template in the Shadow DOM.
Lines 22: registration of a new custom element named <my-widget>. When the browser encounters <my-widget> within an HTML document, it will create an instance of the MyWidget class and render the shadow DOM of the Web Component.
Now, we can use the newly created element and inject content. The template used here is the last one we studied in a previous lesson about HTML templates. Check the full example online at JSBin:
This lesson is only an introduction to custom elements. Here are a few pointers for learners who would like to see how a custom element can inherit from another custom element.
MDN article: Using Custom Elements
From Google devs: Custom Elements v1: Reusable Web Components