How does Angular Shadow use DOM 1


Angular 2: Encapsulation of the view of a component

01/27/2016, fromNikolas Poniros

Update: 02/05/2016 - Some formulations have been corrected. Thanks to Pascal Precht for his feedback.

warning: Angular 2 is still in beta. It is possible that some of the things described here may not work or work differently in the future. Version 2.0.0-beta.1 is used in the article.

It is expected that readers of the article will have a rudimentary knowledge of Angular 2. More information about Angular 2 can be found in our Angular 2 cookbook

Typically, when using CSS to define the design of a web page, the design is applied globally to the web page. It does not matter whether we use inline styles using a style tag or CSS files using a link tag. Angular 2 allows the scope of application of CSS styles to be limited to individual components and their view. This type of limitation is called in Angular 2 View encapsulation. Angular offers three ways to achieve this encapsulation; these are:

  1. No encapsulation (ViewEncapsulation.None)
  2. Emulated encapsulation (ViewEncapsulation.Emulated)
  3. Shadow DOM (ViewEncapsulation.Native)

The options are defined in ViewEncapsulation. We will now take a closer look at these three possibilities.

No encapsulation

In this case, no encapsulation is applied and all CSS styles are applied as usual. This is the default behavior if a component does not define its own CSS styles. If our component defines its own CSS styles, we can enforce this behavior by setting the encapsulation property of the view to ViewEncapsulation.None. Of course, we can also use CSS styles that we have defined globally in the template of our component.

Example component with CSS styles and ViewEncapsulation.None

DOM generated from our component


As we can see here, the CSS styles are extracted from the component template and defined globally in the head element. The problem with this: If several components define the box class or if the box class has already been defined globally, the later definitions of the class will overwrite the initial behavior of "box". In a small project, it is not difficult to use unique names for the CSS classes, but the larger the project, the more difficult it becomes. Above all, the risk of styles being overwritten increases when using 3rd party components that have also set ViewEncapsulation.None.

Emulated encapsulation

In this case, the CSS styles that we define in our component are encapsulated by global CSS styles and by CSS styles that define other components. The CSS styles of our component are only applied to the component's template. This is the default behavior when a component defines its own CSS styles. If a component does not define any CSS styles, we can enforce this behavior by setting ViewEncapsulation.Emulated for the encapsulation property. CSS styles that have been defined globally can still be used in our component.

Example component with CSS styles and ViewEncapsulation.None

DOM generated from our component


Just like in the example without encapsulation, our CSS styles were written in the head element. Only this time an attribute is added to the CSS selector. If we take a closer look at the DOM, we will see that the div in which my-app-tag also has exactly this attribute. With the help of HTML attributes, Angular can limit the scope of a CSS style. In this case, the scope of the box class is limited to elements with the _ngcontent-khh-1 attribute. Angular is smart enough to only assign this specific attribute to elements of our my-app component. Other components have different attributes.

One or the other reader may now wonder what the _nghost-khh-1 attribute means and why we call this type of encapsulation “emulated”. Emulated refers to the real encapsulation that can be achieved through the Shadow DOM. When we use the Shadow DOM, a shadow root generated and thereby our tag (here "my-app") becomes a so-called host element. The content of the template property becomes the content of the shadow DOM. Since “my-app” is a host element, it has the designation “_nghost” in the name of the attribute. The three characters after the minus define an internal name for our component, and the number indicates the depth at which a component is located. If we had For example, another component within the my-app component would have the number 2.

The advantage of ViewEncapsulation.Emulated is that you can achieve adequate encapsulation of the CSS styles of individual components even without shadow DOM support. CSS styles defined in components have no effect on globally defined CSS styles.

Shadow DOM

With the help of the Shadow DOM we can completely encapsulate our component from global CSS styles and from those of other components. However, the browser must support the Shadow DOM API so that we can use this encapsulation option. Currently, the Shadow DOM API is only supported by Chrome and Opera. To use Shadow DOM we have to set the encapsulation property to ViewEncapsulation.Native.

Example component with CSS styles and ViewEncapsulation.Native

DOM generated from our component


This time the CSS styles of the component were not written in the head element, but as part of the content in the shadow root. The HTML template of the template property and the CSS styles of the component form the content for the Shadow DOM. Everything that is in the shadow root is separated from the rest of the DOM structure.

With Shadow DOM, we can achieve the greatest possible encapsulation, but only if the browser also supports Shadow DOM. For now, emulated encapsulation is our best option and also the one I would recommend.