Understanding Angular’s ViewEncapsulation

Arjen Brandenburgh
Apr 1 · 6 min read

In your Angular components you’re able to specify a component’s ViewEncapsulation. It defines template and style encapsulation options available for components, and thus specifies the strategy on how styles are applied to a component. By default, styles are appended to the document’s and is encapsulation emulated, but there are other options as well.

Shadow DOM

Before we can get into the ViewEncapsulation options, we first have to know about the Shadow DOM. In an HTML document all styles and elements are in one global scope and can be accessed through a . The selector will always find the object, no matter where or how deep the element is nested in the DOM. This also applies to the CSS selectors. While there are advantages to this behaviour, for example, a single CSS class can style everything it applies to immediately, there are also situations where you want elements to be encapsulated from the rest of the DOM.

iframe example from w3schools.com

A popular and easy to understand example are elements, which encapsulate a document. They are designed to embed a full document within HTML. You don’t want your iframe to be affected by the global styling of your parent document. Iframes are not using the Shadow DOM though, since its DOM elements are in a completely separate context, but you’re still basically creating “a DOM within a DOM”, which is comparable to what the Shadow DOM does. This notion is not a new concept, but has only recently been opened for use by web developers. Browsers have internally used it for a longer time to create complex components. For example, the input range selector looks like this under the hood in Chrome:

<input type=”range”>

Shadow DOM was introduced to address DOM tree encapsulation problems. So how does Angular leverage the Shadow DOM? An Angular application consists out of components with their own template and styles. When creating a component, Angular can render this component in a shadowRoot. This shadowRoot is the Shadow DOM for that component, and gives us encapsulation for the component out of the box. Easy enough, right?

There is a small problem however. The Shadow DOM isn’t supported by all browsers yet. So where does that leave us?

Screenshot from https://caniuse.com

Angular doesn’t use the Shadow DOM by default, but rather emulates Shadow DOM behaviour. We can however tell a component how the encapsulation should be applied to the component through the .


ViewEncapsulation Types

Angular has three options (or four, depending on how you view it) to encapsulate a component. You specify the in your component decorator like this:

import { Component, ViewEncapsulation } from '@angular/core';@Component({
selector: 'app-encapsulation-emulated',
templateUrl: 'encapsulation-emulated.component.html,
stylesUrl: 'encapsulation-emulated.styles.scss',
encapsulation: ViewEncapsulation.Emulated
})

ViewEncapsulation.None

When using this encapsulation strategy, you’re telling Angular to not encapsulate at all. Meaning it doesn’t use the Shadow DOM and all styles applied to the component are appended to the document head. The styles apply to the entire document and thus are applied globally.

import { Component, ViewEncapsulation } from '@angular/core';@Component({
selector: 'app-encapsulation-none',
template: `
<div [ngClass]="toggledClass ? 'green' : 'red'">
<ng-content></ng-content>
<button (click)="toggle()">Toggle me</button>
</div>
`,
styles: [`
.green {
background: green;
}
.red {
background: red;
}`],
encapsulation: ViewEncapsulation.None
})
export class NoneComponent {
toggledClass = false;
toggle() {
this.toggledClass = !this.toggledClass;
}
}

If we have this component, we can see that styles are added to the <head> and the template is rendered.

Rendering with ViewEncapsulation.None

This is the only strategy that allows CSS to cross component boundaries. This can both be an advantage or a disadvantage. You may have a use case where you want the stylings to leak over to other parts of the website.

ViewEncapsulation.Emulated

When you’re not specifying an encapsulation strategy, this is the default one that Angular applies to your component. This is a powerful Angular feature that really shows what Angular is capable of. It doesn’t use the Shadow DOM, but rather emulates the behaviour. Angular will add attributes to the component’s templates and rewrites the CSS by applying these there as well.

That may sound kind of vague, so let’s show what that means.

Rendering with ViewEncapsulation.Emulated

Here you see that Angular added attributes to our elements, and applied these same attributes to our CSS. The styles are still written to the head of our document, but only the elements in this component have this unique attribute. Meaning, while the styles are still global, they will only apply to our “scoped” component.

We’re not using the Shadow DOM, meaning that also browsers without Shadow DOM support are able to properly view this component.

ViewEncapsulation.ShadowDom

This encapsulation strategy utilises the Shadow DOM, so it renders a component with its own shadowRoot.

With this strategy, there’s also a secret fourth one: . This uses a now deprecated version of the browser’s native shadow DOM implementation. If you want to know about these changes, you can read about those here.

Rendering with ViewEncapsulation.ShadowDom

This time no screenshot of the head-tag, because… there’s nothing appended there. Everything is right here, including the styles, encapsulated in this isolated #shadow-root node.


Summary

So does this article describe everything what the Shadow DOM is all about? No, definitely not, the Shadow DOM depicts so much more than what we’ve discussed.

However, we have seen how Angular can work together with the Shadow DOM and also how it can emulate this in such a way that it is supported by all browsers. Now if you want to toy around a bit, you can use this Stackblitz where I’ve created components with all three strategies.


Looking for a job in Amsterdam?

I work for Sytac as a Senior Front-end developer and we are looking for medior/senior developers that specialise in Angular, React, Java or Scala. Sytac is a very ambitious consultancy company in the Netherlands that works for a lot of renowned companies in banking, airline, government and retail sectors. You can think of companies like ING, KLM, Deloitte, Ahold Delhaize, ABN AMRO, Flora holland and many more.

From a personal opinion Sytac really sets itself apart with their client portfolio, but also with how they take care of their employees. They do really care about the wellbeing of their employees. Apart from a good salary (50K-75k), you will notice this in regular meetings with the consultant managers but also by the amount of events they organise and all the other perks they offer to keep all employees happy.

If you think you have what it takes to work with the best, send me an email on arjen.brandenburgh@sytac.io and I’ll be happy to tell you more.

Dev Jam

DevJam is a community that aims to enable software professionals to explore new technologies and to stay on top of every thing development.

Arjen Brandenburgh

Written by

Senior Front-end Developer from the Netherlands @ Sytac

Dev Jam

Dev Jam

DevJam is a community that aims to enable software professionals to explore new technologies and to stay on top of every thing development.