220

How and where can one use ::ng-deep in Angular 4?

Actually I want to overwrite some of the CSS properties of the child components from the parent components. Moreover is it supported on IE11?

starball
  • 20,030
  • 7
  • 43
  • 238
Jeyabalan Thavamani
  • 3,057
  • 8
  • 21
  • 33
  • Since `/deep/` and `::ng-deep` are both deprecated, I suggest you to take alook to this answer https://stackoverflow.com/a/49308475/2275011 and comments for more details and solutions. – Ferie May 21 '19 at 10:32

7 Answers7

188

Usually /deep/ “shadow-piercing” combinator can be used to force a style down to child components. This selector had an alias >>> and now has another one called ::ng-deep.

since /deep/ combinator has been deprecated, it is recommended to use ::ng-deep

For example:

<div class="overview tab-pane" id="overview" role="tabpanel" [innerHTML]="project?.getContent( 'DETAILS')"></div>

and css

.overview {
    ::ng-deep {
        p {
            &:last-child {
                margin-bottom: 0;
            }
        }
    }
}

it will be applied to child components

Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
Sajeetharan
  • 216,225
  • 63
  • 350
  • 396
142

I would emphasize the importance of limiting the ::ng-deep to only children of a component by requiring the parent to be an encapsulated css class.

For this to work it's important to use the ::ng-deep after the parent, not before otherwise it would apply to all the classes with the same name the moment the component is loaded.

Using the :host keyword before ::ng-deep will handle this automatically:

:host ::ng-deep .mat-checkbox-layout

Alternatively you can achieve the same behavior by adding a component scoped CSS class before the ::ng-deep keyword:

.my-component ::ng-deep .mat-checkbox-layout {
    background-color: aqua;
}

Component template:

<h1 class="my-component">
    <mat-checkbox ....></mat-checkbox>
</h1>

Resulting (Angular generated) css will then include the uniquely generated name and apply only to its own component instance:

.my-component[_ngcontent-c1] .mat-checkbox-layout {
    background-color: aqua;
}
Vedran
  • 10,369
  • 5
  • 50
  • 57
  • 16
    man, your answer `my-component ::ng-deep...` just saved my day. I spent all day trying to apply a style for my component with ng-deep and was overriding my all components, from my entire application. – Cristiano Bombazar Oct 11 '19 at 18:47
  • 2
    Worth noting: "In order to scope the specified style to the current component and all its descendants [but not globally], be sure to include the :host selector before ::ng-deep." From: https://angular.io/guide/component-styles – StvnBrkdll Aug 05 '20 at 15:05
  • Should be the accepted answer given the precise explanations – Timtim Feb 22 '21 at 18:46
131

USAGE

::ng-deep, >>> and /deep/ disable view encapsulation for specific CSS rules, in other words, it gives you access to DOM elements, which are not in your component's HTML. For example, if you're using Angular Material (or any other third-party library like this), some generated elements are outside of your component's area (such as dialog) and you can't access those elements directly or using a regular CSS way. If you want to change the styles of those elements, you can use one of those three things, for example:

::ng-deep .mat-dialog {
  /* styles here */
}

For now Angular team recommends making "deep" manipulations only with EMULATED view encapsulation.

DEPRECATION

"deep" manipulations are actually deprecated too, BUT it's still working for now, because Angular does pre-processing support (don't rush to refuse ::ng-deep today, take a look at deprecation practices first).

Anyway, before following this way, I recommend you to take a look at disabling view encapsulation approach (which is not ideal too, it allows your styles to leak into other components), but in some cases, it's a better way. If you decided to disable view encapsulation, it's strongly recommended to use specific classes to avoid CSS rules intersection, and finally, avoid a mess in your stylesheets. It's really easy to disable right in the component's .ts file:

@Component({
  selector: '',
  template: '',
  styles: [''],
  encapsulation: ViewEncapsulation.None  // Use to disable CSS Encapsulation for this component
})

You can find more info about the view encapsulation in this article.

P.S.
  • 15,970
  • 14
  • 62
  • 86
  • 4
    Disabling view encapsulation applies all CSS in your component globally. – Vedran Mar 25 '19 at 16:04
  • 50
    Don't use `ViewEncapsulation.None`! It will make a lot of damage by making those styles possible to leak into other components. – Alex Klaus May 04 '19 at 12:12
  • To add: it will NOT unload the CSS once the component is unloaded either, aka super inconsistent and break-y CSS – Sammaye Mar 05 '23 at 12:32
  • The `::ng-deep` feature seems to have been removed from the latest version of chrome -> [Read more](https://chromestatus.com/feature/6750456638341120) – Raphaël Balet Apr 21 '23 at 08:57
39

Make sure not to miss the explanation of :host-context which is directly above ::ng-deep in the angular guide : https://angular.io/guide/component-styles. I missed it up until now and wish I'd seen it sooner.

::ng-deep is often necessary when you didn't write the component and don't have access to its source, but :host-context can be a very useful option when you do.

For example I have a black <h1> header inside a component I designed, and I want the ability to change it to white when it's displayed on a dark themed background.

If I didn't have access to the source I may have to do this in the css for the parent:

.theme-dark widget-box ::ng-deep h1 { color: white; }

But instead with :host-context you can do this inside the component.

 h1 
 {
     color: black;       // default color

     :host-context(.theme-dark) &
     {
         color: white;   // color for dark-theme
     }

     // OR set an attribute 'outside' with [attr.theme]="'dark'"

     :host-context([theme='dark']) &
     {
         color: white;   // color for dark-theme
     }
 }

This will look anywhere in the component chain for .theme-dark and apply the css to the h1 if found. This is a good alternative to relying too much on ::ng-deep which while often necessary is somewhat of an anti-pattern.

In this case the & is replaced by the h1 (that's how sass/scss works) so you can define your 'normal' and themed/alternative css right next to each other which is very handy.

Be careful to get the correct number of :. For ::ng-deep there are two and for :host-context only one.

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
  • You can also use `:host(.theme-dark)` if you don't want to inherit `theme-dark` from any parent components. This will entirely depend on your site css design. Also attributes can be very useful and can be combined in sophisticated ways in css alone `:host([theme='dark']:not([dayofweek='tuesday'))` – Simon_Weaver Aug 07 '18 at 23:22
  • Also note that this follows normal css rules, so if you have a component as described above (with host-context css) inside a container which has a `.theme-light` class this is in turn nested inside a container with `.theme-dark` it will still pick up the `theme-dark` and apply the css. But this is a great solution for 'modernizr' type classes, or if you have a theme set globally and only once. – Simon_Weaver Nov 07 '18 at 19:55
  • Can I use :host-context instead of ::ng-deep ? – eddy Jun 21 '20 at 22:23
  • @eddy I’m too sleepy right now to fully think this through, but host-context is almost like ng-deep but going UP the DOM tree instead of down. So it’s absolutely not equivalent but you could – Simon_Weaver Jun 22 '20 at 04:29
2

Just an update:

You should use ::ng-deep instead of /deep/ which seems to be deprecated.

Per documentation:

The shadow-piercing descendant combinator is deprecated and support is being removed from major browsers and tools. As such we plan to drop support in Angular (for all 3 of /deep/, >>> and ::ng-deep). Until then ::ng-deep should be preferred for a broader compatibility with the tools.

You can find it here

Dmitriy
  • 5,525
  • 12
  • 25
  • 38
gr4viton
  • 1,434
  • 1
  • 8
  • 21
  • 8
    In this text it clearly says ::ng-deep is also deprecated: "we plan to drop support in Angular (for all 3 of /deep/, >>> and ::ng-deep)". – adripanico Dec 13 '18 at 08:40
0

I looked through all those answers and found nobody mentioned a child component can pass a style CSS in from its parent.

In component ts file, you can use this:

   @Input() styles: any = {};  

In component html file, you use this:

[ngStyle]="styles"

in parent, you use this :

<yourComponent [styles]="{backgroundColor: 'blue', 'font-size': '16px'}">

Please see more details here: Best way to pass styling to a component

In this way, we didn't break encapsulation, which is one of those most important Object orientation principles

Justin
  • 1,050
  • 11
  • 26
-5

Use ::ng-deep with caution. I used it throughout my app to set the material design toolbar color to different colors throughout my app only to find that when the app was in testing the toolbar colors step on each other. Come to find out it is because these styles becomes global, see this article Here is a working code solution that doesn't bleed into other components.

<mat-toolbar #subbar>
...
</mat-toolbar>

export class BypartSubBarComponent implements AfterViewInit {
  @ViewChild('subbar', { static: false }) subbar: MatToolbar;
  constructor(
    private renderer: Renderer2) { }
  ngAfterViewInit() {
    this.renderer.setStyle(
      this.subbar._elementRef.nativeElement, 'backgroundColor', 'red');
  }

}
Post Impatica
  • 14,999
  • 9
  • 67
  • 78