What Are Custom Elements?
One of the more exciting updates to the JavaScript language, in my opinion, and many others, is JavaScript components. The update gives the ability to create custom HTML elements with JavaScript and use them within your HTML. If you’ve used React, the UI framework, then you’ve seen something very similar in action before. They are almost identical to what’s known within the framework as React components. The exciting thing is that we can use these in front-end programming with vanilla JavaScript or in server-side programming, as well.
Another feature of components is that there are two different kinds. Of course you can completely customize an element, which is known as ‘autonomous’[1], or you can extend the functionality of an existing HTML element. Let’s go ahead and look at some examples so that it might make a little bit more sense.
The first kind of custom element we’ll take a look at will be one which extends the functionality of an existing HTML element. In this case, we’ll be creating an element that takes the functionality of the button element and displays a pop-up modal when the button is pressed.
Customizing Existing HTML Elements
class ModalBtn extends HTMLButtonElement {
constructor() {
super();
window.onLoad = function() {
const modal = document.querySelector('#modal');
this.addEventListener('click', openModal);
function openModal() {
modal.style.display = 'block';
}
}
};
}
customElements.define('modal-btn', ModalBtn, { extends: 'button' });
Okay, so what’s going on here? If you have some experience with JavaScript, it should be fairly easy to tell. We are creating a class called ‘ModalBtn’ which is extending the functionality of the HTML button element, just meaning that we want to add to it. We then call our constructor method which is going to house the code we want to add to the button. You’ll notice that ‘super();’ is called immediately after the constructor is called. You’ll want to call super(); each time before your code so that the correct prototype chain can be established.[2] Without it, we won’t be able to use this parent’s function, thus destroying all new functionality of our button here.
The next thing you’ll notice is that we’re putting our code within another function (window.onLoad). This just ensures that our HTML web page loads everything that it needs to before our script does. You could experience potential issues if it doesn’t load last. Luckily, you can put it inside a function as we did above, or you can simply place your script tag at the bottom of your HTML body, which most people do anyway as good practice.
Once we’ve made sure that our JavaScript will load last, we can add the event listener for our button by using the ‘this’ keyword. We then specify that we want a ‘click’ event and that we want the function, ‘openModal’, to run whenever the button is clicked. The openModal function simply sets the modal’s display to ‘block’ making it visible on the web page.
The last thing we must do in order to use it within our HTML code is define the custom element. The customElements.define() method takes in two or three parameters. The first parameter is the name that we’ll use within our HTML, the second parameter is the name of the class we created, and the third parameter, if any, is the HTML element that you’re element is extending the functionality of. So, in this case, we write ‘{ extends: ‘button’ }. Now that the button functionality is complete, we could use it wherever we want within our project. Within our HTML, it’s going to look like this:
You can also create and add custom properties to the elements as well. Click here for further reading and to see how this is done.
Autonomous Elements
As I mentioned before, autonomous elements are completely customized. They don’t piggy-back off of the functionality of existing HTML elements. Let’s go ahead and take a look at an example. In this example, we are creating a custom element that displays an error message for when something has gone awry on your web page.
class ErrMsg extends HTMLElement {
constructor(){
super();
let text = this.getAttribute('text');
let div = document.createElement('div');
let para = document.createElement('p');
let strong = document.createElement('strong');
para.style.color = 'red';
div.appendChild(para);
para.appendChild(strong);
strong.textContent = text;
}
}
customElements.define('error-message', ErrMsg);
In this example, we create a class called ‘ErrMsg’ that extends the HTML element interface[1]. We don’t need to add ‘Button’ between ‘HTML’ and ‘Element’ because we are not extending functionality for the button element or any other existing HTML element, for that matter. We are creating our own. Once again, we use the constructor method and call props as the first thing we do inside the method.
The rest of the code is simply putting the element together. We get the element’s ‘text’ attribute (which we’ll set once we place the element in our HTML), create several DOM elements, style the text color, and then arrange our elements. So, the entire outer div along with everything inside of it will be our custom element. Last, but definitely not least, we register our custom element by defining it with customElements.define. Since we’re not extending the functionality of any existing element, we don’t need the curly braces with the key pair. Within our HTML, it’s going to look something like this:
It’s very similar to the button element we created in the last section. We did create a custom property called ‘text’ in this one, and we set the element’s text content to be equal to the property. So, whatever we specify there will show up as the visible content within our element.
Summary
Don’t be intimidated by concepts like this. Upon first glance, it may just seem like another something else we need to learn, but once you start playing around with them, you begin recognizing its parts. If you have some experience or knowledge with and around classes in JavaScript, you should have no problem creating some of your own custom elements.
The more you practice, the better you’ll get and the more you’ll understand the convenience and power of JavaScript components, and specifically, custom elements. Aside from their usefulness in creating rich websites, learning more about this subject helped me better understand what was going on within React.js, Flutter, and other programming frameworks and languages.
Related: JavaScript Modules: An Introduction
Further Reading
> MDN on Using Custom Elements
> JavaScript.info on Custom Elements
References
1. Using Custom Elements by MDN