One way of fixing this problem is through the Shadow DOM.
Shadow DOM provides the following solutions:
To demonstrate Shadow DOM, we are going to use a simple component called
tuts-tabs. All references in this post will point to this piece of code. To experience the Shadow DOM, just take a look at the demo below:
Before you start to code with the Shadow DOM, you need to understand the regular DOM.
HTML acts as the backbone of a web site. In just a few minutes you can create a page. When you open that page in a browser, the DOM starts to come into play. Once the browser loads a page, it starts to parse HTML into a data model. This data model is a tree structure with nodes. These nodes represent the elements in your HTML. This data model is easy to modify and manipulate with code.
The downside is that your entire web page or even complex web application is treated as a single data structure. This is not very easy to debug! For example, CSS styles that are intended for one component can end up affecting another component elsewhere in your app.
When you want to isolate one part of your interface from the rest, you can use
iframes. But, iframes are heavy, and extremely restrictive.
That’s why Shadow DOM was introduced. It is a powerful capability of modern browsers that allows web devlopers to include subtree of various elements in the DOM. These subtrees of the DOM don’t affect the main document tree. Technically, these are known as a shadow tree.
The shadow tree has a shadow root which gets attached to a parent in the DOM. This parent is known as the shadow host.
For example, if you have
<input type="range"> plugged into a browser that is powered by WebKit, it will translate to a slider. Why? This is a slider because one of the subtree DOM element understands the “range” to change its appearance and introduce slider-like functionalities. This is an advantage Shadow DOM brings to the tab.
element.attachShadow() to create a Shadow DOM element.
In our example,
tuts-tab, you will see this link of code for creating the Shadow DOM element.
Next, we will add content to the shadow root using
.innerHTML. Note that this is not the only way of populating your Shadow DOM. There are many APIs to help you populate the Shadow DOM.
As we extend
HTMLElement, it is important to call
super() inside the constructor. Also, the constructor is where the shadowRoot needs to be created.
shadowRoot is created, you can create
CSS rules for it. The CSS rules can be enclosed in the
<style> tag, and these styles will be only scoped to
CSS related to the
tuts-tab can be written inside the
<style></style> tags. Remember, all styles declared here will be scoped to the
tuts-tab web component. Scoped CSS is a useful feature of Shadow DOM. And, it has the following properties:
If you want to select the custom element inside the shadow DOM, you can make use of the
:host pseudo-class. When the
:host pseudoclass is used in a normal DOM structure, it would not have any impact. But, inside a shadow DOM, it makes a very big difference. You will find the following
:host style in the
tuts-tab component. It decides the display, and the font style. This is just a simple example to show how you can incorporate
:host in your shadow DOM.
One catch with
:host is its specificity. If the parent page has a
:host, it will be of higher specificity. All styles inside the parent style would win. This is a way of overriding styles inside the custom element, from outside.
As your CSS becomes simpler, the overall efficiency of the shadow DOM improves.
All the styles defined below are local to the shadow root.
Likewise, you have the freedom to introduce stylesheets within the shadow DOM. When you link stylesheets inside the shadow DOM, they will be scoped within the shadow tree. Here is a simple example to help you understand this concept.
Next, we can define the HTML elements of our
In a simple tab structure, there should be titles that can be clicked and a panel that reflects the contents of the selected title. This clearly mean, our custom element should have a
div with titles, and a
div for the panel. The HTML components will be defined as below:
Inside the panels
div, you will come across an interesting tag called
<slot>. Our next step is to learn more about slots.
Slot plays a crucial role in the Shadow DOM API. A slot acts as a placeholder inside custom components. These components can be filled by your own markup. There are three different types of slot declaration:
tuts-tabs, we have one named slot for the tab titles, and another slot for the panel. The named slot creates holes that you can reference by name.
Now, it is time to populate the slots. In our previous tutorial, we learnt about four different methods for defining custom elements. The tuts-tabs uses two of those methods for building the tab:
connectedCallback we will populate the slot defined in step 6. Our
connectedCallback will be defined as below. We make use of
querySelector to identify the
panelsSlot. Of course, this is not the only way of identifying slots in your HTML.
Once the slots are identified, you need to assign nodes to it. In
tuts-tab, we use the following
tabsSlot.assignedNodes to identify the number of tabs.
connectedCallback is where we would register all the event listeners. Whenever the user clicks on a tab title, the content of the panel needs to change. Event listeners for achieving this can be registered in the
We are not going to drill deep into the logic, on how to implement tabs and its functionality. However, remember that the following methods are implemented in our custom
tuts-tab component for switching between tabs:
Moving on, don’t forget to define the
disconnectedCallback. This is a lifecycle method in custom elements. When the custom element is destroyed from the view, this callback gets triggered. This is one of the best places to remove action listeners, and reset controls in your application. However, the callback is scoped to the custom element. In our case, it would be
The final step is to use
tuts-tab in our HTML. We can insert
tuts-tab, quite easily in the HTML markup. Here is a simple example to demonstrate its usage.
There we go! We have come to the end of an important tutorial where we create and use a custom element. The process is simple, and it proves to be extremely useful while developing web pages. We hope you try creating custom elements, and share your experiences with us.