Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What to use in place of ::ng-deep

Tags:

html

css

angular

People also ask

What use instead of :: ng-deep?

There is no alternative to ::ng-deep. In Angular, like in any other framework, sometimes you have to style a child component based from a parent component. Since Angular provides encapsulation of CSS (what is great!)

What is :: ng-deep in CSS?

::ng-deep is what's called a shadow-piercing descendant combinator. It works because it is able to pierce the shadow DOM. Using ::ng-deep to override a child components styles will achieve the desired result but with unintended side effects.

Why we should not use Ng-deep?

Angular's API states that the ng-deep psuedo-class is deprecated. completely disables view-encapsulation for that rule. If we use it without the :host pseudo-class, it will make the style-rule global, not a good thing. There's something odd about Angular view encapsulation which gets style specificity wrong.

Can we use NG-deep in CSS?

Applying the ::ng-deep pseudo-class to any CSS rule completely disables view-encapsulation for that rule. Any style with ::ng-deep applied becomes a global style. In order to scope the specified style to the current component and all its descendants, be sure to include the :host selector before ::ng-deep .


FWIW In my research I have not found any replacement for ng-deep or the other applicable alternatives. This is because, I believe, the Angular team is deferring to the W3C spec on the shadow dom, which initially had selectors such as deep. However, the W3c has since removed the recommendation, but not replaced it with a new one. Until that happens, I imagine that the Angular team will keep ::ng-deep and it's alternatives available, but in deprecated state due to the pending state of W3C's drafts. I am not able to take the time to find the documentation to back this up right now but I did see it recently.

Long story short: Keep using ::ng-deep and its alternatives until a replacement is created - the deprecation is just an early notice so that people aren't blindsided whenever the actual change materializes.

-- UPDATE --

https://drafts.csswg.org/css-scoping-1/ Here is the draft proposal if you're interested. It appears that they are working on a robust set of selectors for elements within a shadow dom tree; it is this spec, once approved, that I think will inform the angular clone, if there even is one (i.e. angular may not need to implement their own selectors once this goes live in browsers).


The simple and easy alternative to a deep style is a common style using the element selector of the parent component. So if you had this in hero-details.component.css:

:host ::ng-deep h3 {
  font-style: italic;
}

It would become this in styles.css:

app-hero-details h3 {
  font-style: italic;
}

Basically a deep style is an un-encapsulated style so it conceptually seems more like a common style to me than a component style. Personally I would not use deep styles anymore. Breaking changes are normal in major version updates and deprecated feature removal is fair game.


To bypass the deprecated ::ng-deep, I usually disable ViewEncapsulation. Although this is not the best approach, it has served me well.

To disable ViewEncapsulation, do the following in your component:

import { Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
  encapsulation: ViewEncapsulation.None
})

export class HeaderComponent {

}

This will make the .scss styles in this component global to the whole application. To not allow the styles to go up the chain to parent and sibling components, wrap the whole scss with the selector like so:

app-header {
  // your styles here and any child component styles can go here
}

Now, the styles specified here will go down to children components so you have to be extra specific with your css selectors and mind your p's and q's when adding CSS (maybe add the child selector specified in your Angular app and then its styles).

I say it is not the best approach because of the paragraph above, but this has served me well.


As someone stated before, if you're using a third party library it's virtually impossible to avoid having to use ::ng-deep once in a while. But what are you going to do about your previous projects when the ::ng-deep became no longer supported by browsers?

To be ready for that moment I will suggest the following:

  1. Use ViewEncapsulation.None wisely. Which translates to only for those components that needs to access deeper components.
@Component({
      selector: 'app-example',
      templateUrl: './example.component.html',
      styleUrls: ['./example.component.scss'],
      encapsulation: ViewEncapsulation.None
    })
  1. Now, to avoid collisions and CSS weirdness you should (as a rule) always wrap your component's template with a class. So, example.component.html should be like:
<section class="app-example-container">
<!-- a third party component -->
<mat-tab-group>
<mat-tab label="First"></mat-tab>
<mat-tab label="Second"></mat-tab>
</mat-tab-group>
</section>
  1. Again, by rule, the first line of every single SCSS file will target the component container. Since there's no Encapsulation you can modify the third party component by targeting their classes. That said, example.component.scss should be like:
.app-example-container {
/* All the CSS code goes here */
.mat-tab-group .mat-tab-label {color: red;}
}

A self note to the future: https://angular.io/guide/component-styles
That should be the first place to look at for official alternatives/ways-to-go