Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

View Encapsulation In Angular

4.91/5 (4 votes)
26 Dec 2019CPOL6 min read 7K   35  
We will see how view encapsulation is achieved in Angular.

Introduction

This article is all about what view encapsulation (Scoped style) is and how it is achieved in Angular.

Prerequisite

I am assuming that all readers have a prior knowledge of Angular 2 and above versions and what component is and how CSS is applied to a component.

Idea Of View Encapsulation

As we know in Angular, the CSS applied to one component is scoped to that component only and does not leak outside that template. But how does this work.

Before we reach there, we have to know the concept of Shadow DOM. ShadowDom is basically a specification that enables DOM tree and style encapsulation. In simple words, we can say it allows us to apply scoped style to elements without bleeding out to the outer world. This is a new kind of feature of browsers and not all browsers at this time support this.

Let me show you shadowDOM in action.

JavaScript
var elm = document.querySelector('myfav');

elm.innerHtml = `<style>h1 {color : blue} </style>
                 <h1>Test</h1>`;

So you guys must be familiar with this plain JavaScript code. Here, we are just having an element reference of myfav element (myfav here could be any Angular component) with the help of querySelector method. Now we have element reference so with the help of innerHtml property, we are setting a color of h1 to blue.

But there is a problem with this approach. The problem here is that this style leaks outside this element. So if I have another h1 somewhere else, this style will be applied to that also. We don't want that. If we are making a component and have some styles to it, we would like to have those styles be scoped to that component only. Or for other case, let's say we want to use a component developed by some other folks and they might have defined some styles under that component and when we bring that component in our application, we don't want those styles to override the styles in our application and that's where shadow DOM shines.

We can change the above code and can use shadow dome with just an extra line of code like below:

JavaScript
var elm = document.querySelector('myfav'); 

var root = elm.createShadowRoot();

root.innerHtml = `<style>h1 {color : blue} </style>
                 <h1>Test</h1>`;

So here, after we get the reference of the element in elm variable, we simply call createShadowRoot() method and this gives us root of shadowDOM for that element. Then, instead of using innerHtml property of the element reference, we use innerHtml property of shadowroot and with this, the style of our h1 style will be scoped to this h1 element and will not leak outside of this element. This is shadowDOM.

You might wonder what this has to do with Angular. So answer to that, as I have earlier mentioned, this shadowDOM is not supported by all browsers as of now so to have this feature, Angular has used a trick of its own or we can say Angular has emulated the shadowDOM.

Angular is achieving functionality of shadowDOM through its concept called ViewEncapsulation. This is an enum which has three properties:

  • Emulated
  • Native
  • None

Let's see through the code how these values works.

Note: Here, I am assuming that you all know what component is and how component is created. Here I am using courses component which will render list of courses. You can use your own component and logic inside that, as while illustrating this example, our main focus is going to have on component metadata not on logic inside component.

Shown below is our simple courses component with its metadata.

Image 1

Now to have the ViewEncapsulation, we will use encapsulation property of components metadata and will assign ViewEncapsulation enum values to it like below.

Note: For using viewencapsulation property of metadata, we have to import ViewEncapsulation from @angular/core.

Image 2

When we hit the browser on localost:4200, we will see the below page with a list of courses and by default, the first one is selected.

Image 3

Now here, we will see how Angular has a functionality of scoped style or functionality of shadowDOM. Ok, while inspecting an HTML in browser window of Angular application, you guys must have noticed _ngcontent[id] on all the HTML elements and on your custom component. This is the only guy who is playing the major or we can say most of the role in achieving Angular a scoped style.

So hit browser console again and inspect the rendered HTML. In the <head> section, there will be all styles listed used in this HTML. From all the listed styles, expand our style that we have used for our component in component's CSS file.

Image 4

Here, you may be noticing [_ngcontent-c1] attribute that is dynamically applied to the span.active by Angular. So you may be guessing what this attribute is for.

Image 5

So to answer that, you might be noticing above in our <app-courses> element which is our host element for our courses component, inside our <app-courses> element, there is a <div> and inside that <div>, there is a <span>. You can see here that _ngcontent-c1 attribute is applied here as well which we were guessing what this attribute is for.

So Angular attaches an attribute to our element and uses that attribute to post process our CSS likes in the above shown example Angular attaches _ngcontent-c1 to the div and the same is used in our CSS too. In this way, that CSS will be applied only to that element which will have that span.active class as well as _ngcontent-c1 attribute. If you look anywhere in this document, you will not find _ngcontent-c1 attribute anywhere else. Also, we don't have to worry about how this attribute will be generated and how it will be applied. It's purely an Angular job to do.

In this way, Angular tries to emulate the concept of shadowDOM in its framework. Also, this is the default behaviour of Angular means to have emulated view encapsulation, we don't have to use that encapsulation property in our metadata.

Now, we will see how Native property of ViewEncapsulation enum works. As we have already mentioned, this will not work on all the browsers but to demonstrate, we will see how it works as on my browser.

Change the ViewEncapsulation enum value to Native in component metadata.

Image 6

Now, on browser, hit the inspect button and open the browser console. Again, in head section, we have three styles, but you may notice that there is no fourth style where we had our post process CSS rule.

Image 7

Now if you scroll down, under <app-courses> element, we have shadow-root (marked in black above). Under the shadow-root, we have style element and span.active class is applied here. So it does not have an additional attribute. All the style is scoped here. In this way, Native property works.

Now, the third property of ViewEncapsulation is None. If we use this property in our component metadata, the style will be leaked to other element also.

History

  • 26th December, 2019: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)