Angular View Encapsulation
How does Angular View Encapsulation work
What is view encapsulation in angular?
In Angular, a component’s styles can be encapsulated within the component’s host element so that they don’t affect the rest of the application.
-Angular Official Docs
In simple words, it means if you write styles for component “A” it will not affect component “B” or any other component
We have three options in view encapsulation
- ViewEncapsulation.Emulated — (Default enabled) Encapsulate styles using attributes
- ViewEncapsulation.ShadowDom — Encapsulate styles using the browser’s built-in Shadow DOM API
- ViewEncapsulation.None — Don’t encapsulate styles
ViewEncapsulation.Emulated
Before we understand how emulated works, we must understand the CSS attribute selector
We have one input and a div element in vanilla HTML and CSS
To select the above input and div element in CSS, you can use its attribute
See it in action below, Click on Result
More on attribute selector here
Fine, let's come back to the angular component, If you inspect your component HTML which has ViewEncapsulation.Emulated, It will look something like this
Notice the attributes? _nghost-* _ngcontent-* It is generated by angular while compiling the application
_nghost-*is added to the host element i.eapp-component-aandapp-component-b_ngcontent-*is added to all of the content inside the components
These attributes are uniquely generated for each component that has ViewEncapsulation.Emulated
Also, notice how CSS contains these attributes, h1[_ngcontent-*] this way angular encapsulate styles and make sure they don’t affect any other component
ViewEncapsulation.ShadowDom
This encapsulation purpose is also the same(don’t bleed styles out of the component), But instead of unique attributes Angular uses the browser’s built-in ShadowDom to encapsulate component styles
If you inspect the ShadowDom enabled component HTML, it will look something like this
Notice we don’t have that ugly attributes in HTML and as well as in CSS, If it doesn’t have unique attributes how styles are encapsulated?
Now our component contains something called shadow-root and it contains our styles which make sure it applies styles to its inside content only(not outside component)
But how does ShadowDom works?
To understand this we must understand the ShadowDom scope, In simple words, it is the same as the JavaScript scope for let and const
If ViewEncapsulation.ShadowDom works the same and doesn’t have ugly attributes then why not use it for all components?
Get Sameer Khan’s stories in your inbox
Join Medium for free to get updates from this writer.
As ShadowDom is not supported in old browsers, we cannot use it and this is the same reason Emulated is enabled by default
ViewEncapsulation.None
This option is to disable encapsulation completely for the component
This means if you write styles in the component which has ViewEncapsulation.None enabled that is like writing styles in styles.scss(Global styles)
Mostly this option will be used by third-party libraries such as Angular Material and PrimeNG
Bonus #1
We also had ViewEncapsulation.Native which is deprecated in favor of ViewEncapsulation.ShadowDom
- ViewEncapsulation.Native — Uses ShadowDom v.0
- ViewEncapsulation.ShadowDom — Use ShadowDom v.1
Bonus #2
What is ::ng-deep and :host?
Note:
ng-deepis deprecated and there is no alternative for this currently, But you don’t have to worry, Because I believe once angular have an alternative, they will automatically replace theng-deepwhen you runng update(read ng-deep deprecation here)
::ng-deep
As you know ViewEncapsulation.None disables encapsulation completely for the entire component, Is there a way to partially disable encapsulation?
Yes, that's were ::ng-deep comes in, example below
But why do you want to do that? why do you want to disable encapsulation partially?
If you have used third-party libraries then you may have already noticed that the HTML of the third-party libraries don’t get encapsulation attributes as they have disabled it using ViewEncapsulation.None
And when we try to customize the third-party library content it won't take any effect, because our component has ViewEncapsulation.Emulated enabled
Let’s take a component with a third-party library included and customize it, The example below is having a PrimeNG button but the concept is the same for any third-party library(Angular Material for example)
//compiled app.component.scss
.p-button[_ngcontent-*] {
background: red !important;
}I have added the above styles to change the background of the PrimeNG button, but It doesn’t change
If you notice the above image, the PrimeNG button doesn’t have any attribute in HTML as ViewEncapsulation is disabled and my styles have attributes because ViewEncapsulation is enabled.
To solve this issue we can use ::ng-deep to partially disable encapsulation
//app.component.scss::ng-deep .p-button {
background: red !important; //not scoped, same as writing in global
}.other-el {
color: blue; //scoped to app.component
}
Yay! Now It works
Wait, It is applying those styles to all the components, What If I want to apply styles to a single component?
Then you can use any parent selector or :host
:host
Remember that attribute(_nghost-*) which angular adds to the component’s host element? Using this special selector you can customize the third-party library and still scope styles to the component itself, So styles don’t bleed to any other component
//app.component.scss:host ::ng-deep .p-button {
background: red !important; // scoped to app.component only
}
Cheers🎉




