Web development represents such a high percentage of the software industry, and as a consequence, new JavaScript frameworks appear continuously, with the promise of solving the problems of existing frameworks (and which will surely introduce new ones, of course), in these days when there are so many possibilities to choose from, choosing the framework for your next project becomes tedious and often ends up being chosen based on sympathy rather than the requirements of the project itself.
I bring you another possibility, but it is not a framework but rather a set of native APIs.
No, it's not the holy grail of front-end development, but it's a promising alternative that, throughout this series of articles, we'll be uncovering together, investigating each technology in particular and then combining them, and deciding along the way whether it's worth it or not.
Although we won't come to an absolute conclusion, I invite you to join me on this journey of discovery.
What are Web Components?
All modern JavaScript frameworks like Angular or Vue and libraries like React, among others, give you code reusability in the form of components.
Generally speaking, these are shareable and standalone pieces of code (HTML/CSS/JS) that offer visual style and interactivity and, if necessary, have an API for customization.
Web Components allow you to create those components without using a framework. It’s a suite of web platform APIs that are used together, allowing you to create new custom, reusable HTML tags with encapsulated styling and functionality and utilize them in your web apps.
Why use Web Components?
Besides being framework-agnostic, they are also compatible with any frontend framework or JavaScript library, so you can use the same Web Component across different projects no matter what framework they use.
This is especially useful for micro frontend projects or big companies that use other platforms, providing a simple library of shared components for any project with any technology.
Web Components Specifications
There is a discrepancy regarding the technologies that make up Web Component specifications, the most widely accepted are Custom Elements, Shadow Dom, and HTML Templates, but I would like to add a fourth to that triumvirate, ES Module.
The only mandatory technology is Custom Elements, and you can pick the ones that best suit your requirements.
Custom Elements, defined in the HTML Living Standard Specification
Shadow DOM, defined in the DOM Living Standard Specification
HTML Templates, defined in the HTML Living Standard Specification
ES Modules, defined in ECMAScript Language Specification
Custom Elements
Custom Elements are a vital feature, the core one to me, of Web Components, as their name implies, are HTML elements, like <form>, <div>, <button>, but something you can name yourself. They allow you to create your custom HTML tag with their behavior, properties, and methods and can be shared across frameworks and browsers.
You need a JavaScript class that extends the base HTML Element to define a new HTML element.
With that done, you must register the custom element using the CustomElementRegistry.define() method. This method takes arguments.
A string representing the name you are giving to the element; note that custom element names must have at least one hyphen (kebab-case); they can’t be single words, to never clash with elements officially supported in the HTML specification.
A class that defines the behavior of the element.
(Optional) An options object containing an extends property specifies the built-in your element inherits from if any (only necessary when you are extending a built-in element).
Now you can use your custom element on your page like any other HTML tag.
Also, you can create dynamically using JavaScript.
Shadow DOM
The Shadow DOM are JavaScripts APIs for attaching its own encapsulated hidden DOM tree to an element; this shadow DOM is rendered separately from the main DOM (light DOM), allowing you to isolate styling and functionality inside the element effectively.
This shadow DOM starts with a shadow root which you can attach any element in the same way as the light DOM; its elements are not visible to querySelector from the document object, so you can use the same id for an element inside the shadow DOM that it’s using for a component in the light DOM without conflict.
Also, shadow DOM has its stylesheets, styles rules from the other DOM are not applied.
You can attach a shadow root to any element using the Element.attachShadow() method. This takes as its parameter an options object that contains one option, mode, with the value of “open” or “closed.”
Mode open means you can access the shadow DOM using JavaScript written in the main page context, for example, using the Element.shadowRoot property:
Note that still are two separate DOM (shadow and light), but you can access from the light DOM to the shadow DOM elements.
A shadow root can include content from its containing document using the <slot> tag. Using slots, you can put content from the outer document in designated spots in your shadow root.
HTML Templates
The HTML <template> element is a unique tag that allows you to create HTML code snippets that are not rendered immediately when a page is loaded but can be used later at runtime using JavaScript.
A <template> contains an HTML fragment you can access using the content property, a read-only DocumentFragment containing the DOM subtree the template represents.
This code won’t render anything on your page until you grab a reference to it with JavaScript and append it to the DOM.
Just keep in mind that if you use the content property directly, the template will empty after appending, so the next time you try to append will just add empty contents.
To avoid this, you should clone or import it using cloneNode or importNode.
ES Modules
You know what I'm talking about if you’ve worked on a modern JavaScript project. EcmaScript Modules allow you to split large source code projects into small files, enhancing readability and reusability to reduce complexity.
You can define variables, classes, or functions and decide which will be available from other modules; oppositely, you can import those from other modules and use them.
All major browsers support modules import now, then you don’t need a bundler, preprocessor, or transpiler, you just must tell the browser that a script should be treated as a module by using script type=”module”
The one that wasn't meant to be
Originally, HTML import was meant to be one of the APIs of Web Components, a technology developed by Google (and shipped to Chrome at some moment but not supported anymore), but that concept was never adopted as a standard; the other browser vendors had no plans to ship the feature.
It’s a pity HTML imports were an excellent way to declare the HTML structure and included the component's JavaScript logic.
To sum up
In this article, we introduced Web Components and overviewed the APIs we can use to craft Web Components.
In subsequent articles, we will take a deep dive into each of them, its features, use cases, and how to use them in the Web Components context (remember that these are web APIs whose use is not exclusive to Web Components, you can use them independently), to finalize combine all of them in our Web Component.
Resources: