DEV Community

John Peters
John Peters

Posted on • Updated on

Angular 10 - Avoid using ::ng-deep (ngdeep)


Attempts to get CSS specificity within the Angular View Component's CSS sheet often fail. Our Style markup just can't go deep enough to find the elements we want. We know we're doing it right because our Javascript based QuerySelector works, but trying the same selection in CSS of the component just fails!


We used SCSS for the core, but all Views were using CSS.


First, what is deep? I found issues when attempting to override stylings mostly for Material Components but, have had my own (parent) components present challenges when reused elsewhere. Let's just call "Deep" any styling not directly related to the current component.

CSS Query Selectors within a View's component style, are being ignored by Angular anytime we attempt to change a "deep" style. With Angular, it's simply wrong to assume we can affect "deep" styles within any given component.


If we want addressability to any style in the project, we simply move our markup to the root level SCSS style sheet to accomplish it.

Perhaps it works so well because it bypasses Angular's View Encapsulation rules.

Just don't use NG-Deep; it kind-of sort-of works but all the red flags are out on it and forget going too deep. Just use root level specific SCSS selectors as shown here!

 ng-select {
    padding: 0.25rem 0 0.25rem 0.25rem;
    border-style: none;
    border-bottom: 1px solid $Color-BlueGreen;
    font-family: $Font-Alternate;
    width: 100%;

    .ng-dropdown-panel {
      background-color: red;
      .ng-option:hover {
        background-color: yellow;
        width: 100%;
      .ng-option {
        background-color: white;
        padding-top: 0.3em;
        padding-left: 0.3em;
        cursor: pointer;
    .ng-select-container {
      .ng-value-container {
        .ng-input {
          input {
             // Works every time!
            width: 100%; 
            // Five Levels Deep
Enter fullscreen mode Exit fullscreen mode

Here's another example of avoiding :ng-deep! This was in the core.scss stylesheet. It worked first time!

app-parent {
  app-child-grid {
    app-child-edit.cdk-drag {
      form {
        div {
          // 6 levels deep from the app-parent
          ng-select {
            width: 101%;
      .className {
        app-custom-control {
          // Still had to override this one
          justify-content: end !important;
          margin-right: 2em;
          .buttons {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(3em, 1fr));
            min-width: 6em;
            margin-bottom: 0.5em;
            button {
              max-width: 5em;
            div[name="faIconSave"] {
              justify-self: end;
              margin-right: 0.7em;
Enter fullscreen mode Exit fullscreen mode

The demo above shows 6 levels of depth that altered the style on the first attempt! 10 minutes to perfection and addressability vs. days to try to kind-of sort-of get NG-Deep to work.

*How We Figured This Out! *

Angular's API states that the ng-deep psuedo-class is deprecated.

Furthermore; it states that ng-deep

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. How do we know? If we write a Typescript QuerySelectorAll we can pull any ID or Class on the page regardless of depth.

But if we use a CSS selector in the component's StyleSheet, looking for the same ID... Angular doesn't find it when the depth is deep. This, to me is a design flaw.

This forces us to write Typescript QuerySelectors for our component's ele.NativeElement to narrow the search; but we don't really want to do that. We prefer all styling in the StyeSheet of the component.

Old Solution Was
If we ignore the ::ng-deep deprecation warning for now, (after all, it's still working in Angular 10); we come up with specific rules following this format.

// Note we don't need the ID
// We just go for the className
// This still allows for cascading

Enter fullscreen mode Exit fullscreen mode

This code functions the same as using a query selector, removing the old class name and adding in the new class name:

let element = 
Enter fullscreen mode Exit fullscreen mode

We can spend a ton of time trying to write more specific CSS selectors (no guarantee that Angular's View Encapsultion) will find them, or we just use this pattern...

Enter fullscreen mode Exit fullscreen mode

Best Option
We found the best option is to use Less or Sass to build very specific style rules, this works better than ng-deep!

JWP 2020

Top comments (7)

lifelongthinker profile image

Maybe I can shed some light on this: Angular works with "pseudo" view encapsulation (Angular shadow DOM). Templates are assigned specific class identifiers. Your stylesheets are then compiled with those class identifiers baked into them. This is Angular's way of mimicking view encapsulation.

When you query the DOM at runtime, you see the final markup composed by Angular with the class identifiers assigned. That's why TD can query the elements but your style sheet selectors don't work. They basically work against two different CSS truths.

lifelongthinker profile image
Sebastian • Edited

One more thing: I have started refraining from using ng-deep() while :host and :host-context are pretty useful.

Instead, I use global app style includes that basically lie in the component folders and are called '' (my notation). These are included in the global app styles and thus left untouched by the Angular compiler.

jwp profile image
John Peters • Edited

Sebastion; I tried :host-context yesterday, it worked a bit deeper but not all the way into a 4 or 5 level deep component. I may be doing something incorrect in my css selectors. Just not sure yet.

Thread Thread
lifelongthinker profile image

I am experiencing similar issues. It seems the selectors are extremely picky. This is what I do when debugging those issues:

  1. Check if the CSS in question has indeed be compiled into the final stylesheet(s).
  2. Check in the Browser Dev Tools if the CSS in question is being applied to the intended elements, or (if not) where and why they are overriden by other styles.
  3. Try to target said elements through a CSS selector in the global style sheet to see if component isolation is the issue.
Thread Thread
jwp profile image
John Peters • Edited

Okay just figured out another clue to this puzzle, in the data below this is how the browser style page show the order. Material Components do late CSS binding somehow, it makes things hard to fix because those styles have highest specificity.

.mat-button[disabled], .mat-icon-button[disabled], .mat-stroked-button[disabled], .mat-flat-button[disabled] {
    cursor: default;

.mat-icon-button {
    padding: 0;
    min-width: 0;
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    line-height: 40px;
    border-radius: 50%;
.mat-button, .mat-icon-button, .mat-stroked-button, .mat-flat-button {
    box-sizing: border-box;
    position: relative;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    cursor: pointer;
    outline: none;
    border: none;
    -webkit-tap-highlight-color: transparent;
    display: inline-block;
    white-space: nowrap;
    text-decoration: none;
    vertical-align: baseline;
    text-align: center;
    margin: 0;
    min-width: 64px;
    line-height: 36px;
    padding: 0 16px;
    border-radius: 4px;
    overflow: visible;

// This was ::ng-deep but only !important made it work

.mat-icon-button {
    width: 1em !important;
    height: 1em !important;

They say don't use important but I know of no other way to get my style rules to the top other than setting them in javascript at the element layer which is at the top of rule list. Everything else was intrinsic to the material controls.

annadore profile image

In angular material 15 unfortunately these cases are not working. If anybody know how to remove ::ng-deep there - please, leave the comment

mrezatabaa profile image
Reza Tabaa

How may I view the HTML file?