Can I Use Web Components
Josselin d'Espinay15 min read
The goal of this article is to show you what is a web component, why you can now use it in production, and when you should do so.
For all those who already have some knowledge in web components, I would like to specify that I will be talking about the web component V1 standards as the v0 draft APIs are now removed from Chrome since Chrome 80.
If you’re new to web components, don’t worry you can catch up starting from the v1 standards, looking at the v0 specifications and standards might not be useful unless you want to understand the journey of the web components to reach its V1.
But first, you might want to be able to understand the basic concepts of a web component.
Definition of a web component
So first and foremost, what is a web component?
Simply put, the web component is not just a thing by itself. For a component to be called so, different technologies have to be combined.
What are those “different technologies” then?
I will go through the different technologies that make a web component. This article won’t be able to encompass all the possibilities of a web component and all its possible implementations. For those who would like to go further into the explanations, I will provide some resources as you read through.
Custom elements
A web component is nothing more than an enhanced custom element. A custom element is a javascript class expanding the HTMLElement class that allows you to create a new HTML tag for your component.
First, you have to create a class as shown in the script below.
class MyComponent extends HTMLElement {
constructor() {
super();
...
}
}
We then define a custom element with the previously created class.
customElements.define("my-component", MyComponent);
Your custom element is ready to be used as a tag in any web project.
<my-component></my-component>
let’s try it in a simple html document:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>my first custom element</title>
</head>
<body>
<my-component></my-component>
<script>
class MyComponent extends HTMLElement {
constructor() {
super();
}
}
customElements.define("my-component", MyComponent);
</script>
</body>
</html>
And that’s it! you have created a custom element. Now if you inspect your HTML document on a web browser you should be able to see something like this:
The main idea of custom elements is that you can create, extend, and reuse them everywhere in your code.
If you are looking for a more in-depth documentation, check the official documentation. I would also recommend this article on customElements that is giving you a good overview of the matter.
Shadow DOM
The next technology that we will be discussing is the Shadow DOM. When you attach a shadow DOM to your custom element you then scope all the CSS, and the HTML in this DOM. The big idea of the shadow DOM is to be able to create templates for your web components that won’t be affected by any style or js selectors and therefore keep your code and feature as intended.
Let’s try it in our previously created component :
First create a shadow root:
const shadowRoot = this.attachShadow({ mode: "open" });
If you want to know more about the attachShadow mode argument I strongly recommend this article from Leon Revill.
Create some elements:
const spanElement = document.createElement("span");
spanElement.textContent = "Hello world";
Create a style element:
const style = document.createElement("style");
Create a css class for your span element and add some css rules:
style.textContent = ".my-class {color: red}";
spanElement.setAttribute("class", "my-class");
And finally attach them to your shadow root:
shadowRoot.appendChild(style);
shadowRoot.appendChild(spanElement);
so here it what your component should look like now:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>my first custom element</title>
</head>
<body>
<my-component></my-component>
<script>
class MyComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: "open" });
const spanElement = document.createElement("span");
spanElement.textContent = "Hello world";
spanElement.setAttribute("class", "my-class");
const style = document.createElement("style");
style.textContent = ".my-class {color: red;}";
shadowRoot.appendChild(style);
shadowRoot.appendChild(spanElement);
}
}
customElements.define("my-component", MyComponent);
</script>
</body>
</html>
Now you can try going to the console and access and modify the elements in the shadow DOM but you won’t be able to.
As well if you add some style in your HTML file, it won’t affect the shadow DOM elements. Try adding style on the span element for example:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>my first custom element</title>
<style>
span {
color: blue;
}
</style>
</head>
<body>
<span>Hey! I am just here for the example tho...</span>
<my-component></my-component>
<script>
{...}
</script>
</body>
</html>
As you can see the span inside the shadow DOM is not affected by the style.
HTML Template
This means that you can define a template for your Web component and clone it for every instance of your component.
So first you create your template:
const template = document.createElement("template");
template.innerHTML = `
<style>
span { color: red; }
</style>
<span>Hey There! I am in the template </p>
`;
Then you can clone it’s content into your shadow tree:
shadowRoot.appendChild(template.content.cloneNode(true));
As I am sure you noticed, we don’t just add the template in the shadowRoot but instead we copy its content. That’s because Templates are not rendered so what we need for our component is the content of the template.
Let’s implement it in our component:
export class MyComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: "open" });
const template = document.createElement("template");
template.innerHTML = `
<style>
span { color: red; }
</style>
<span>Hey There! I am in the template </span>`;
shadowRoot.appendChild(template.content.cloneNode(true));
}
}
The important point to keep in mind about templates is that it allows you to declare chunks of HTML in your document that will be rendered and that sole purpose is to be cloned and reused. It is a perfect fit for web components.
You could define it in your index.html
since template elements are not rendered in the browser but I would recommend keeping it close to your component declaration to keep your index.html
file clean and organize your templates by component.
You can even use the slot Element to make your template more flexible. Those of you who already worked with Vue.js may be familiar with the concept of slot. For the others Slots are like placeholder. They allow the developper to create specific elements that will be placed inside the parents component DOM at predifined emplacement.
Imagine that your component template is a text with holes, each hole has an id.
When you add children to your component, you can assign them a slot
attribute.
This slot attribute allows your component to place them in the “holes ” according to their ids (the slot attributes).
If you want to learn more about slot element with web component I would recommend this documentation from MDN.
The addition of those four standards-based technologies is what defines the web component today.
ES Modules
This part is not always explicit in the definition of a web component. It doesn’t affect the component on itself but more the way you will be able to use it in a project.
The ES modules should allow developers to use the script tag with the type module.
Wich means you can export variables or components from your .mjs
files and import it in your .html
file within a module script tag.
The ES modules standard allow developers to reuse web component in any HTML file by importing them from an mjs file.
// wc.mjs
export class MyComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: "open" });
const spanElement = document.createElement("span");
spanElement.textContent = "Hello world";
spanElement.setAttribute("class", "my-class");
const style = document.createElement("style");
style.textContent = ".my-class {color: red;}";
shadowRoot.appendChild(style);
shadowRoot.appendChild(spanElement);
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>my first custom element</title>
<style>
span {
color: blue;
}
</style>
</head>
<body>
<span>Hey! i am just here for the example tho...</span>
<my-component></my-component>
<script type="module">
import { MyComponent } from "./wc.mjs";
customElements.define("my-component", MyComponent);
</script>
</body>
</html>
If you are interested in how the ES module works I strongly advise that you read this article from Lin Clark.
Can I use it?
Now, a lot of developers are still quite reluctant to use web components in their projects. And you can understand why! The lack of common standards implemented by all major browsers since it’s creation in the early 2010s has allowed many web component libraries to raise and grow sub-communities that do not share the same opinion on the definition of a web component and its implementation.
On the article Why the React community is missing the point about Web Components by Ben Halpern in November 2018, Dan Abramov comments the following :
So I think some important points have to be clarified for you to understand the implication of using it in your projects.
Web components are tools
It is important to understand that Web components are not designed to be better than HTML elements. We can consider web components as a tool to extend HTML, not to replace it.
And as we know the same tool cannot be used for all projects. So before adding this tool to your toolbox make sure you really need it or else it might some unecessary weight.
Here are some points that you should consider before jumping in :
-
It is not that simple to write a web component. It can be quite complex and verbose depending on the scope of your web components. And most of the project with quite a large number of web components have been using some libraries to creates them. webcomponents.org has a page dedicated to those libraries.
-
Comparing a web component and a react component for example is like comparing apples and oranges. The definition of a web component is not setting limits to what you can put in it. React in its documentation explain it this way:
Understanding and defining what will be the interfaces between web components and the rest of your project’s tools is important.
-
Web component v1 standards are not that old and you probably want your project to work on older browsers versions too. Simply put, you might need polyfills. I will come back to it later on.
-
One of the down points of the web component often cited is that developers have been struggling to use it with server-side rendering. This is mainly caused by the fact that the contents of ShadowDOM are often missing when the view is delivered to the client. One possibility is to remove the shadow dom from your component like you can see in this article. Other web component advocates found ways to make it work like in this article by Steve Belovarich or this one by Peter Goes. I think you can sum it up by saying that for now there are no standards for server-side rendering with a web component but you can always find a workaround.
Just remember to take all this point in account before jumping in.
Future proof
One of the main arguments of the pro web component community is that web components are future proof. Since it is based on web Standards, it is now supported by all modern browsers and should always be.
I can already hear your ask:
Well you are right to be worried about them and that should be one of your main concerns.
Below are the previously cited technologies browser supports at the current date. If you want the latest data, click on the link below each of them.
can i use custom shadow DOM v1
can i use javascript module script tag
can i use javascript module dynamic import
As you can see neither Internet explorer is not supporting any of them neither the early versions of other browsers.
There are polyfills for the web component APIs. You can use the official polyfills.
With those polyfills, nothing you can now develop your future and past proof web component!
Reusability
A web component is easily reusable and is trustworthy. Its strong encapsulation provides security for its data. It also ensures that it will be used the way its designer intended to.
Should I use it?
Based on previous points, there are no specific reasons to not go for it. Still, the Web component isn’t mature enough to be trusted for production by most developers. It solves problems but adds others.
For now, the best use the community can agree on for a WC-based project is a design system UI components library. Tesla for example, has crossed the bridge and chosen to make its design system with web components.
Building a sustainable design system can be a real brain teaser for companies. Big companies often use a lot of different technologies and frameworks for all their products.
They reach a point where sustainability becomes a problem in terms of design and technology. They ask themselves those questions :
- Do we have to create a UI component library for each framework that we use?
- How can we be sure that we don’t switch framework in the next few years?
- And If we make sure we don’t, aren’t we missing an opportunity?
A web component is not based on any framework owned by any company but on standards adopted by all major browsers. You don’t have to worry about the hype effect on your chosen technology or framework. This is why web components fit if you decide to create a UI component Library or even a design system.
Of course, you can also use it in any static pages project but I wanted to highlight the one big use where you should consider it.
Conclusion
Now that the standards that define Web components are implemented in every modern browser, they are meant to be part of the future of the web.
As a web developer, it’s time to consider web components as a practical solution for your features and problems.
I would like to quote Serhii Kulykov(@webpadawan) on this article
Of course when the technology will be more mature, accepted and integrated into our projects we will witness the apparition of new ideas and maybe even new standards.
But for now, we are the ones who have to be bold enough to try on our own.
If you are interested in the subject, I recommend the following articles:
The journey of Web Components: wrong ways, lacking parts and promising paths - Serhii Kulykov
Why I don’t use web components? - Rich Harris (svelte creator).
I recommend you read the article but most importantly to read its comment. Especially this gist that is a direct answer to the previously mentioned article
Why the React community is missing the point about Web Components - Ben Halpern.
Once again the interesting part is mostly in the comments with a discussion between Dan Abramov et Benny Powers