Web Components are a relatively new set of technologies that lets you create custom HTML elements using the shadow DOM. This enables you to write markup, styles and logic once and reuse it around your website or web app! In this article, we are going to look into the technologies which power Web Components and create a custom HTML element from scratch!
Shadow DOM… What is DOM?
For the uninitiated, DOM stands for Document Object Model. It is a tree-like structure generated by a web browser like Google Chrome to represent the contents of a web page.
Example
Consider the following HTML document:
<!DOCTYPE html>
<html>
<head>
<title>An Example HTML Document</title>
</head>
<body>
<h1>Yay</h1>
</body>
</html>
This document when represented as the DOM, looks something like this:

More from GeekyMinds: Progressive Web Apps Made Easy
Shadow DOM – The Most Simple Explanation
Let’s consider the HTML <video>
tag for a moment. We use it to put videos on our websites for the world to see. But have you considered the fact that you did not need to write any markup or styling for the video player?
The markup, styles, etc associated with <video>
Can you think of any other HTML tag that uses shadow DOM? Comment down below!
Keep in mind, the shadow DOM is just like the regular DOM under the hood. Therefore, it fully supports the DOM API. Using it, you can create custom elements which can be reused in your app’s user interface.
The markup is defined once along with the styling and scripting. Since shadow DOM is rendered separately, there’s no chance of your code colliding with other code in the page.
Shadow DOM Terminology
Now let’s go a bit deeper and learn about a few important terminologies!
Shadow Host – Remember, the Shadow DOM is a DOM tree by itself. If you want to use it in your document, you’ll have to attach it to your regular DOM. The shadow host is the node that the shadow DOM is attached to.
Shadow Tree – The tree inside the shadow DOM is known as the shadow tree. Easy!
Shadow Root – The root node of the shadow tree. The entire shadow tree is attached to or hangs from, this node.

Custom Elements
Custom Elements are one of the key features of Web Components. As stated before, it lets you write code once and reuse it in other places. Custom elements can inherit from existing native HTML elements if you require it.
This gives us two types of custom elements:
1. Autonomous custom elements
- They do not inherit from existing elements
- Usage:
<custom-element></custom-element>
2. Customized built-in elements
- These inherit from existing HTML elements
- Usage:
<p is="custom-element"></p>
When you inherit from a native HTML element, you cannot use the custom element’s name directly. For example, if we make a custom-element
which inherits <p>
Building A Custom Element From Scratch
Okay, enough theory. The best way to understand shadow DOM is by creating a custom element. To keep the article from getting too long, we are only going to make an autonomous custom element. Let’s get coding!
Todo List UI Using Custom Elements

Here you can see the Todo list app UI we are going to build. The tasks you see listed are built using a custom element called <todo-item>
which has a text
attribute.
Point to note: The custom element tag needs to be in kebab-case
. This is compulsory.
More from GeekyMinds: JavaScript Promises Explained!
Here Are The Steps
- Write the custom element
- Register the custom element
- Use it in our markup
Writing the custom element
In order to write the custom element, we will need to define a class for it. By convention, use PascalCase
for naming the class. Do not forget to extend HTMLElement
.
We are going to use two new methods: Element.attachShadow()
and customElements.define()
. I have explained them right after the script below!
The rest is documented using comments and should be fairly self-explanatory. If you have doubts, do not hesitate to use the comment section below.
Here’s The Script
class TodoItem extends HTMLElement {
constructor() {
// Always call super first
super();
// Create a shadow root
const shadow = this.attachShadow({ mode: "open" });
// Create <div class="flex"></div>
const div = document.createElement("div");
div.setAttribute("class", "flex");
// Write some CSS to apply to the shadow DOM
const style = document.createElement("style");
style.textContent = `
// Omitted the styles to keep code short
// Refer to CodePen below for full code
`;
// Get todo text
let text;
if (this.hasAttribute("text")) {
text = this.getAttribute("text");
} else {
text = null;
console.error("Error: text attribute missing.");
}
// Set div innerHTML
div.innerHTML = `
<div class="text">${text}</div>
<div class="btn">✖</div>
`;
// Attach the created elements to the shadow DOM
shadow.appendChild(style);
shadow.appendChild(div);
}
}
// Define the new element
customElements.define('todo-item', TodoItem);
Element.attachShadow()
As stated above in the terminology section, we will need to attach the shadow DOM tree we create to the document using an existing element of the DOM. This is done using the Element.attachShadow()
method.
The method takes one parameter, an options
object, containing one key
called mode
. It can have two values: open
or closed
. Setting the mode to open
will allow accessing the shadow DOM from JavaScript written in the main document.
let shadow = elementRef.attachShadow({mode: 'open'});
let shadow = elementRef.attachShadow({mode: 'closed'});
customElements.define()
The define()
method of the CustomElementRegistry
interface allows us to register the custom element we create. It takes two compulsory parameters: the custom element tag and the constructor for the custom element. Easy peasy!
customElements.define('todo-item', TodoItem);
Here’s The Markup
Notice how the custom element has been used by its tag!
<div class="todo-list">
<div class="todo-header">Todo List</div>
<todo-item text="Take dog out for a walk"></todo-item>
<todo-item text="Get dog food on the way back"></todo-item>
<todo-item text="Feed and cuddle with dog"></todo-item>
</div>
More from GeekyMinds: Difference b/w Websites and Web Apps
The Final Source Code
See the Pen Todo List Using Custom Elements and Shadow DOM by Aritra Mukherjee (@mukherjee96) on CodePen.
Remember, the logic and styling belonging to the custom element are part of the shadow DOM and therefore encapsulated. None of the styles you write for a custom element will interfere with other parts of the user interface.
That’s all folks! Comment down below if you have doubts. We are more than happy to help! 😃