Encapsulation
We know that @Component decorator functions take object, and this object contains a lot of properties. So we will learn about Encapsulation properties in this article.
To understand ViewEncapsulation in Angular, we must first understand the shadow DOM.
Understanding Shadow DOM
In one sentence, Shadow DOM is part of the Web component standard and enables DOM tree and style encapsulation. in practice it means that Shadow DOM allows us to hide the DOM logic behind other elements.
Shadow DOM allows us to apply scoped styles to elements without bleeding into the outside world. This is the new feature in browsers, not in older browsers.
Shadow DOM is compatible by default in Firefox (63 and later), Chrome, Opera and Safari. Edge is also working on an implementation.
Shadow DOM brings encapsulation to HTML elements. The use of Shadow DOM, markup, styles and behaviors are scoped to the element and do not clash with other DOM nodes. Shadow DOM is part of the Web components, which encapsulates the styles and the login of the element.
Angular Components
The Angular components are consist of three things:
- Component class
- Template
- Style
The combination of these three factors makes an angular component reusable in an application. In theory, when you create a component, you create a Web component in some way (the angular components are not Web components) to take advantage of the Shadow DOM. You can also use Angular with browsers, which are not compatible with Shadow DOM because Angular has its own emulation and can emulate Shadow DOM.
To emulate the shadow DOM and encapsulate styles, Angular provides three types of view encapsulation. Are the following:
- Emulated (default): The main HTML styles are propagated to the component. The styles defined in the component's @Component decorator are limited to this component only.
- Native: The main HTML styles are not propagated to the component. The styles defined in the component's @Component decorator are limited to this component only.
- None: the component styles are propagated to the main HTML and therefore are visible to all components of the page. with apps that have None and Native components in the application.. All components with encapsulation None will have their duplicate styles on all components with native encapsulation.
Let's try to understand it by using an example. I created a component, as shown below:
app.component.ts
import { Component, ViewEncapsulation } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], encapsulation: ViewEncapsulation.None }) export class AppComponent { title = 'my parent component'; }
app.component.css
h1 { background: red; color: white; text-transform: uppercase; text-align: center; }
We are configuring the style of h1 in the component CSS.
Now let's create a another component. and below is command to create child component :
ng g c child
ChildComponent as shown below:
child.component.ts
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-child', template: `<h1>{{title}}</h1>` }) export class ChildComponent { title = 'my child app'; constructor() { } }
In ChildComponent, we're also using the h1 tag. To understand the different ViewEncapsulation options, we will modify the AppComponent metadata.
ViewEncapsulation.None
Let's start with ViewEncapsulation.None, in this option:
- 1.There is no shadow DOM.
- 2.Style is not scoped to the component.
While running the application, you'll find that the style h1 has been applied to both components, although we only configure the style in AppComponent. This happened because in AppComponent we set the encapsulation property in ViewEncapsulation.None.
app.component.ts
import { Component, ViewEncapsulation } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], encapsulation: ViewEncapsulation.None }) export class AppComponent { title = 'my parent component'; }
In the browser, when you look at the source code, you will find that the style h1 has been declared in the head section of the DOM.
Therefore, in ViewEncapsulation.None, the style is moved to the DOM header section and is not scoped to the component. There is no shadow DOM for the component and the style of the component can affect all nodes in the DOM.
ViewEncapsulation.Native
Next, let's explore ViewEncapsulation.Native, in this option:
- 1. Angular will create Shadow DOM for the component. (If we want Angular to use the shadow DOM, we can configure the encapsulation parameter to use ViewEncapsulation.Native)
- 2. Style is scoped of the component.
While running the application, you'll find that the style h1 has been applied to both components, even if we configure the style only in AppComponent. This happened because in AppComponent we set the encapsulation property in ViewEncapsulation.Native and use AppChildComponnet as a child in the AppComponent template.
app.component.ts
import { Component, ViewEncapsulation } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], encapsulation: ViewEncapsulation.Native }) export class AppComponent { title = 'my parent component'; }
In the browser, when examining the source code, a shadow DOM will be created for AppComponent and the style is scoped to that.
Therefore, in ViewEncapsulation.Native, Angular creates a shadow DOM, and the style is scoped to this Shadow DOM.
If you cannot see Shadow DOM here, press F1 in the Elements or Console tab of your chrome in Developer Tools. And make sure you have selected this option.
ViewEncapsulation.Emulated
Next, let's explore ViewEncapsulation.Emulated, in this option:
- 1. Angular will not create a shadow DOM for the component.
- 2. The style will be scoped to the component.
- 3. This is the default value for encapsulation.
app.component.ts
import { Component, ViewEncapsulation } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], encapsulation: ViewEncapsulation.Emulated }) export class AppComponent { title = 'my parent component'; }
While running the application, you will find that the AppComponent h1 style does not apply to the AppChildComponent h1. This is due to the emulated scope. In this case, the style is limited to the component only. In this option, Angular emulates only Shadow DOM does not create a real shadow DOM. Therefore, the application that runs on browsers is not compatible with a Shadow DOM and styles are scoped to the component as well.
Let's see how Angular achieves this. In the browser, when you look at the source code, you will find the answer.
Angular created the style in the head section of the DOM and given an arbitrary id to the component. Based on the ID, selector style is scoped to the component.