404

I've got a parent component:

<parent></parent>

And I want to populate this group with child components:

<parent>
  <child></child>
  <child></child>
  <child></child>
</parent>

Parent template:

<div class="parent">
  <!-- Children goes here -->
  <ng-content></ng-content>
</div>

Child template:

<div class="child">Test</div>

Since parent and child are two separate components, their styles are locked to their own scope.

In my parent component I tried doing:

.parent .child {
  // Styles for child
}

But the .child styles are not getting applied to the child components.

I tried using styleUrls to include the parent's stylesheet into child component to solve the scope issue:

// child.component.ts
styleUrls: [
  './parent.component.css',
  './child.component.css',
]

But that didn't help, also tried the other way by fetching the child stylesheet into parent but that didn't help either.

So how do you style child components that are included into a parent component?

danronmoon
  • 3,814
  • 5
  • 34
  • 56
Chrillewoodz
  • 27,055
  • 21
  • 92
  • 175
  • 1
    See also http://stackoverflow.com/questions/34542143/load-external-css-style-into-angular-2-component/34963135#34963135 – Günter Zöchbauer Nov 07 '16 at 08:58
  • See a completely paradigm-friendly, trick-free way in my [answer](https://stackoverflow.com/a/52540505/3345644). – Alexander Abakumov Sep 27 '18 at 15:36
  • Use host-content https://stackoverflow.com/questions/60338819/how-is-it-possible-to-adjust-a-components-css-based-on-a-global-css-class-name – Mohsen Nov 22 '22 at 18:46

22 Answers22

337

Update - Newest Way

Don't do it, if you can avoid it. As Devon Sans points out in the comments: This feature will most likely be deprecated.

Last Update

From Angular 4.3.0 till even now (Angular 12.x), all piercing css combinators were deprecated. Angular team introduced a new combinator ::ng-deep as shown below,

DEMO : https://plnkr.co/edit/RBJIszu14o4svHLQt563?p=preview

styles: [
    `
     :host { color: red; }
     
     :host ::ng-deep parent {
       color:blue;
     }
     :host ::ng-deep child{
       color:orange;
     }
     :host ::ng-deep child.class1 {
       color:yellow;
     }
     :host ::ng-deep child.class2{
       color:pink;
     }
    `
],



template: `
      Angular2                                //red
      <parent>                                //blue
          <child></child>                     //orange
          <child class="class1"></child>      //yellow
          <child class="class2"></child>      //pink
      </parent>      
    `

Old way

You can use encapsulation mode and/or piercing CSS combinators >>>, /deep/ and ::shadow

working example : http://plnkr.co/edit/1RBDGQ?p=preview

styles: [
    `
     :host { color: red; }
     :host >>> parent {
       color:blue;
     }
     :host >>> child{
       color:orange;
     }
     :host >>> child.class1 {
       color:yellow;
     }
     :host >>> child.class2{
       color:pink;
     }
    `
    ],

template: `
  Angular2                                //red
  <parent>                                //blue
      <child></child>                     //orange
      <child class="class1"></child>      //yellow
      <child class="class2"></child>      //pink
  </parent>      
`
Top-Master
  • 7,611
  • 5
  • 39
  • 71
micronyks
  • 54,797
  • 15
  • 112
  • 146
  • Are the piercing CSS combinators needed? Just `.class2` in the plunker still gave the same results. Am I missing something? – adam-beck Feb 13 '17 at 16:13
  • @adam-beck It depends how you want to use `viewencapsulation` property. It plays vital role in it. You also need to learn `shadowDOM`,`viewEcapsulation`. – micronyks Feb 13 '17 at 16:42
  • 3
    Piercing CSS combinators are deprecated in Chrome though – Robin-Hoodie Jun 29 '17 at 08:20
  • 32
    The angular team plans to drop support of ::ng-deep as well. From their docs: "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." https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep. – Devon Sams Oct 05 '17 at 13:51
  • 8
    As long as this stays as an accepted answer, people will be mislead. **::ng-deep** should not be used as @DevonSams points in the comment above. – Kostas Siabanis Feb 16 '18 at 14:49
  • 4
    [`::ng-deep` is now deprecated](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep), I don't recommend using it in future applications – Wilt Feb 13 '20 at 08:46
  • 72
    Deprecating something without providing an alternative is probably not the best solution. – tehlivi Feb 14 '20 at 16:44
  • 4
    [::ng-deep is now deprecated](https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep), [You guys can use this](https://angular.io/guide/component-styles#css-imports) – Raghu Krishnan R Mar 02 '20 at 17:08
  • 1
    @All That means styling child component by the parent is not a good solution anyway – Vincent May 01 '20 at 22:23
  • I have a similar requirement now. And I am confused about it. – Subhasish Oct 20 '20 at 10:40
  • 2
    @Vincent-cm then how would you change the styling of a library ? create your own version of it ? – wadie Jul 20 '21 at 15:58
  • I'm sorry but I'm not fan of the simple "don't do it" answer... Putting library problems aside, if people have the need to do so and it is getting deprecated and all, this certainly because there is a better way to do it no? Either by changing the way we build our component tree? Or is it really just "dump everything in your global css file" thing? – Salketer Jul 13 '23 at 10:02
143

You should NOT use ::ng-deep, it is deprecated. In Angular, the proper way to change the style of children's component from the parent is to use encapsulation (read the warning below to understand the implications):

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

@Component({
    ....
    encapsulation: ViewEncapsulation.None
})

And then, you will be able to modify the css form your component without a need from ::ng-deep

.mat-sort-header-container {
  display: flex;
  justify-content: center;
}

WARNING: Doing this will make all css rules you write for this component to be global.

In order to limit the scope of your css to this component and his child only, add a css class to the top tag of your component and put your css "inside" this tag:

template:

<div class='my-component'>
  <child-component class="first">First</child>
</div>,

Scss file:

.my-component {
  // All your css goes in there in order not to be global
}
Tonio
  • 4,082
  • 4
  • 35
  • 60
  • 11
    This is the best answer IMO, as it is actually a viable alternative to the soon-to-be deprecated `::ng-deep`. Generally, components have their own selector anyway (`,
    `, etc.) so there isn't even any need for a wrapper element with a special class.
    – Alex Walker Feb 19 '20 at 12:01
  • 4
    @AlexWalker This might be the best answer for _your_ situation, but worth mentioning that it only answers half of the OP's question afaict: This method allows CSS to propagate as normal from top to bottom, but, by virtue of throwing away ALL encapsulation, **doesn't limit that styling to children of a specific parent**. If you style the children of parent1 one way and children of parent2 another, those CSS rules will now be fighting each other in both places. That can be mind-numbingly painful (and Angular added encapsulation to avoid it). – ruffin May 19 '20 at 17:51
  • 1
    @ruffin That's exactly why I added the warning in my answer to understand the implication of using this technique and how to "manually encapsulate" using a top css tag on your component – Tonio May 20 '20 at 06:57
  • 2
    @Tonio -- Yep, agreed; was replying directly to Alex rather than you. His comment, "_so there isn't even any need for a wrapper element with a special class_" scared me a little. Maybe for a _specific_ situation, but there's a reason Angular "wastes" time supporting encapsulation. This answer is a workable solution in specific cases, but, as you say, is a potentially dangerous one in general. [MatthewB's solution](https://stackoverflow.com/a/43400775/1028230), eg, styles children while keeping encapsulation (but it gets _really_ messy if you have more than one generation of child components). – ruffin May 20 '20 at 13:48
  • I'm trying to implement this but is not working - could any of you help me out ? - https://stackoverflow.com/questions/67639611/how-to-style-nested-childs-of-component-using-sass-without-using-ng-deep – Mauricio Gracia Gutierrez May 21 '21 at 15:46
  • this works, and the best way is to add some comments in ts file: encapsulation: ViewEncapsulation.None, // warning! this will make the style of this component become global, so wrap them in a local class in scss – yww325 Jun 07 '21 at 21:52
  • This is a good answer. However I'm disappointed with Angular in this. I really don't feel that this is the effect that you want to have with view encapsulation. You want for exactly what the OP has requested, to open up a component so that it can be styled by the component it is nested in. I can see why that might be hard for the Angular team to pull off but this bottom-up permeability seems to be literally the opposite effect that most people would want from such a feature – Peter Nixey Jun 09 '21 at 14:07
  • That's very true, I feel like this Encapsulation option should allow for more flexibility. Not sure why they haven't nailed this yet... – Tonio Jun 09 '21 at 19:43
  • Hoping I'm wrong and was just missing something, but the only way I could get this to work was if `encapsulation: ViewEncapsulation.None` was set both on the child and parent components. That's not an acceptable solution IMO, because it requires that the child component has been coded to "allow" it. In many cases I don't have the ability to modify the child component even if I wanted to. It shouldn't take hacks, jumping through hoops, or fear of being deprecated to allow styles of a component to be tweaked by something higher up. – reads0520 Jun 23 '21 at 17:09
  • @reads0520 I am 100% sure that you don't need to set `encapsulation: ViewEncapsulation.None` on the child to be able to customise it from the parent. Setting `encapsulation: ViewEncapsulation.None` on the parent makes the css you define in the parent's css file "global", so it can access the child's component (and technically it can access absolutely anything as the css is global". If you can send a codepen, I'm happy to check it out – Tonio Jun 24 '21 at 08:05
  • @Tonio I'll need to try to reproduce in a simpler example, and will update here. But in the meantime, have you confirmed that the `ViewEncapsulation` approach will allow override of styles explicitly set by the child component, not just adding new styles? (And without `!important` or jumping through any other hoops?) This was my use case. – reads0520 Jul 05 '21 at 17:36
  • Sorry I was in holidays, in order to override the style set by the child, in addition to `ViewEncapsulation` you need to be more "specific" according to css specificity rules. Probably the styles defined or your "child" component are more specific. Very hard to help without an example. – Tonio Jul 12 '21 at 04:07
  • I have to agree with several of the comments here - Angular makes this WAY harder than it should be. With intelligent naming, there are no conflicts. The parent is EXACTLY the correct place to style reusable child components that need to look different depending on what parent they are in. I encounter this scenario constantly, and Angular makes it a pain in the butt to remember how to handle it correctly. I don't encounter the pain these "countermeasures" are supposed to prevent, but I constantly encounter the pain caused by these same countermeasures. – Tim Hardy Jun 13 '23 at 18:09
63

UPDATE 3:

::ng-deep is also deprecated which means you should not do this at all anymore. It is unclear how this affects things where you need to override styles in child components from a parent component. To me it seems odd if this gets removed completely because how would this affect things as libraries where you need to override styles in a library component?

Comment if you have any insight in this.

UPDATE 2:

Since /deep/ and all other shadow piercing selectors are now deprecated. Angular dropped ::ng-deep which should be used instead for a broader compatibility.

UPDATE:

If using Angular-CLI you need to use /deep/ instead of >>> or else it will not work.

ORIGINAL:

After going to Angular2's Github page and doing a random search for "style" I found this question: Angular 2 - innerHTML styling

Which said to use something that was added in 2.0.0-beta.10, the >>> and ::shadow selectors.

(>>>) (and the equivalent/deep/) and ::shadow were added in 2.0.0-beta.10. They are similar to the shadow DOM CSS combinators (which are deprecated) and only work with encapsulation: ViewEncapsulation.Emulated which is the default in Angular2. They probably also work with ViewEncapsulation.None but are then only ignored because they are not necessary. These combinators are only an intermediate solution until more advanced features for cross-component styling is supported.

So simply doing:

:host >>> .child {}

In parent's stylesheet file solved the issue. Please note, as stated in the quote above, this solution is only intermediate until more advanced cross-component styling is supported.

Chrillewoodz
  • 27,055
  • 21
  • 92
  • 175
24

You should not write CSS rules for a child component elements in a parent component, since an Angular component is a self-contained entity which should explicitly declare what is available for the outside world. If child layout changes in the future, your styles for that child component elements scattered across other components' SCSS files could easily break, thus making your styling very fragile. That's what ViewEncapsulation is for in the case of CSS. Otherwise, it would be the same if you could assign values to private fields of some class from any other class in Object Oriented Programming.

Therefore, what you should do is to define a set of classes you could apply to the child host element and implement how the child responds to them.

Technically, it could be done as follows:

// child.component.html:
<span class="label-1"></span>

// child.component.scss:
:host.child-color-black {
    .label-1 {
        color: black;
    }
}

:host.child-color-blue {
    .label-1 {
        color: blue ;
    }
}

// parent.component.html:
<child class="child-color-black"></child>
<child class="child-color-blue"></child>

In other words, you use :host pseudo-selector provided by Angular + set of CSS classes to define possible child styles in child component itself. You then have the ability to trigger those styles from outside by applying pre-defined classes to the <child> host element.

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
  • Looks like a good solution, is there a parent.component.scss file? if yes, care to give it? – Manohar Reddy Poreddy Dec 14 '18 at 10:57
  • @ManoharReddyPoreddy There should be no styling in a `parent.component.scss` related to the styling of the child component. It's the sole purpose of this approach. Why do you need `parent.component.scss`? – Alexander Abakumov Dec 14 '18 at 15:12
  • Not sure, just know a bit of css. Can you share a full solution on jsbin, or other. Your solution can be a future solution for everyone. – Manohar Reddy Poreddy Dec 15 '18 at 05:45
  • @ManoharReddyPoreddy What do you mean by `a full solution`? What's not working for you when you're trying to paste 3 pieces of code above into your app? – Alexander Abakumov Dec 17 '18 at 16:37
  • oh, there is a mention of ViewEncapsulation in your answer, which looks to be code related as seen here, https://angular.io/api/core/ViewEncapsulation, so thought there is more to your code. – Manohar Reddy Poreddy Dec 17 '18 at 16:56
  • 3
    @ManoharReddyPoreddy I'd suggest you to try those pieces of code in practice first. Then, if you'd run into any issues, you'd have a specific question which I could answer or advice to look into a specific topic to get some understanding of how to fix your issue. I mentioned `ViewEncapsulation` just because its default value is what leads to the OP question. You don't have to assign a different `ViewEncapsulation` for the above code to work. – Alexander Abakumov Dec 17 '18 at 17:13
  • 1
    +1 Thank you. Will come back to take this solution in future, settled for ::ng-deep https://stackoverflow.com/a/36528769/984471 for today. – Manohar Reddy Poreddy Dec 18 '18 at 09:00
  • @DzmitryVasilevsky You don't have control over 3rd party components code. So pretty much obvious, if those 3rd party components' API doesn't follow this principle and they don't provide corresponding API - you've no choice and have to use whatever works. But this case by no means makes my `You should not write CSS rules for a child component elements in a parent component` statement wrong. Ugly 3rd party API could ruin any best practices. Also, the initial Q doesn't say anything about 3rd party components - so you've voluntarily modified the initial Q\task. – Alexander Abakumov Nov 16 '22 at 20:00
  • @DzmitryVasilevsky I don't know what could I add more to my initial answer to you. I can only repeat myself: `the initial Q doesn't say anything about 3rd party components - so you've voluntarily modified the initial Q\task.` That's why my SO answer doesn't target practices regarding 3rd party components. And this is why your use case isn't really relevant to this Q and my SO answer. – Alexander Abakumov Nov 17 '22 at 21:07
22

Sadly it appears that the /deep/ selector is deprecated (at least in Chrome) https://www.chromestatus.com/features/6750456638341120

In short it appears there is (currently) no long term solution other than to somehow get your child component to style things dynamically.

You could pass a style object to your child and have it applied via:
<div [attr.style]="styleobject">

Or if you have a specific style you can use something like:
<div [style.background-color]="colorvar">

More discussion related to this: https://github.com/angular/angular/issues/6511

Matthew B.
  • 684
  • 8
  • 18
16

Had same issue, so if you're using angular2-cli with scss/sass use '/deep/' instead of '>>>', last selector isn't supported yet (but works great with css).

Chrillewoodz
  • 27,055
  • 21
  • 92
  • 175
SergiySev
  • 395
  • 3
  • 8
13

If you want to be more targeted to the actual child component than you should do the follow. This way, if other child components share the same class name, they won't be affected.

Plunker: https://plnkr.co/edit/ooBRp3ROk6fbWPuToytO?p=preview

For example:

import {Component, NgModule } from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>I'm the host parent</h2>
      <child-component class="target1"></child-component><br/>
      <child-component class="target2"></child-component><br/>
      <child-component class="target3"></child-component><br/>
      <child-component class="target4"></child-component><br/>
      <child-component></child-component><br/>
    </div>
  `,
  styles: [`

  /deep/ child-component.target1 .child-box {
      color: red !important; 
      border: 10px solid red !important;
  }  

  /deep/ child-component.target2 .child-box {
      color: purple !important; 
      border: 10px solid purple !important;
  }  

  /deep/ child-component.target3 .child-box {
      color: orange !important; 
      border: 10px solid orange !important;
  }  

  /* this won't work because the target component is spelled incorrectly */
  /deep/ xxxxchild-component.target4 .child-box {
      color: orange !important; 
      border: 10px solid orange !important;
  }  

  /* this will affect any component that has a class name called .child-box */
  /deep/ .child-box {
      color: blue !important; 
      border: 10px solid blue !important;
  }  


  `]
})
export class App {
}

@Component({
  selector: 'child-component',
  template: `
    <div class="child-box">
      Child: This is some text in a box
    </div>
  `,
  styles: [`
    .child-box {
      color: green;    
      border: 1px solid green;
    }
  `]
})
export class ChildComponent {
}


@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, ChildComponent ],
  bootstrap: [ App ]
})
export class AppModule {}

Hope this helps!

codematrix

code5
  • 4,434
  • 2
  • 31
  • 24
12

Actually there is one more option. Which is rather safe. You can use ViewEncapsulation.None BUT put all your component styles into its tag (aka selector). But anyway always prefer some global style plus encapsulated styles.

Here is modified Denis Rybalka example:

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

@Component({
  selector: 'parent',
  styles: [`
    parent {
      .first {
        color:blue;
      }
      .second {
        color:red;
      }
    }
 `],
 template: `
    <div>
      <child class="first">First</child>
      <child class="second">Second</child>
    </div>`,
  encapsulation: ViewEncapsulation.None,
})
export class ParentComponent  {
  constructor() { }
}
ilius33
  • 129
  • 2
  • 5
9

Since /deep/, >>>, and ::ng-deep are all deprecated. The best approach is to use the following in your child component styling

:host-context(.theme-light) h2 {
  background-color: #eef;
}

This will look for the theme-light in any of the ancestors of your child component. See docs here: https://angular.io/guide/component-styles#host-context

Abdullah Adeeb
  • 3,826
  • 1
  • 16
  • 14
7

There are a few options to achieve this in Angular:

1) You can use deep css selectors

:host >>> .childrens {
     color: red;
 }

2) You can also change view encapsulation it's set to Emulated as a default but can be easily changed to Native which uses Shadow DOM native browser implementation, in your case you just need to disable it

For example:`

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

@Component({
  selector: 'parent',
  styles: [`
    .first {
      color:blue;
    }
    .second {
      color:red;
    }
 `],
 template: `
    <div>
      <child class="first">First</child>
      <child class="second">Second</child>
    </div>`,
  encapsulation: ViewEncapsulation.None,
 })
 export class ParentComponent  {
   constructor() {

   }
 }
Denis Rybalka
  • 1,821
  • 3
  • 18
  • 28
6

I find it a lot cleaner to pass an @INPUT variable if you have access to the child component code:

The idea is that the parent tells the child what its state of appearance should be, and the child decides how to display the state. It's a nice architecture

SCSS Way:

.active {
  ::ng-deep md-list-item {
    background-color: #eee;
  }
}

Better way: - use selected variable:

<md-list>
    <a
            *ngFor="let convo of conversations"
            routerLink="/conversations/{{convo.id}}/messages"
            #rla="routerLinkActive"
            routerLinkActive="active">
        <app-conversation
                [selected]="rla.isActive"
                [convo]="convo"></app-conversation>
    </a>
</md-list>
Rusty Rob
  • 16,489
  • 8
  • 100
  • 116
5

As of today (Angular 9), Angular uses a Shadow DOM to display the components as custom HTML elements. One elegant way to style those custom elements might be using custom CSS variables. Here is a generic example:

class ChildElement extends HTMLElement {
  constructor() {
    super();
    
    var shadow = this.attachShadow({mode: 'open'});
    var wrapper = document.createElement('div');
    wrapper.setAttribute('class', 'wrapper');
    
    // Create some CSS to apply to the shadow dom
    var style = document.createElement('style');
    
    style.textContent = `
    
      /* Here we define the default value for the variable --background-clr */
      :host {
        --background-clr: green;
      }
      
      .wrapper {
        width: 100px;
        height: 100px;
        background-color: var(--background-clr);
        border: 1px solid red;
      }
    `;
    
    shadow.appendChild(style);
    shadow.appendChild(wrapper);
  }
}

// Define the new element
customElements.define('child-element', ChildElement);
/* CSS CODE */

/* This element is referred as :host from the point of view of the custom element. Commenting out this CSS will result in the background to be green, as defined in the custom element */

child-element {
  --background-clr: yellow; 
}
<div>
  <child-element></child-element>
</div>

As we can see from the above code, we create a custom element, just like Angular would do for us with every component, and then we override the variable responsible for the background color within the shadow root of the custom element, from the global scope.

In an Angular app, this might be something like:

parent.component.scss

child-element {
  --background-clr: yellow;
}

child-element.component.scss

:host {
  --background-clr: green;
}

.wrapper {
  width: 100px;
  height: 100px;
  background-color: var(--background-clr);
  border: 1px solid red;
}
vivanov
  • 1,422
  • 3
  • 21
  • 29
3

What I prefer to achieve this is the following:

use @Component to add css class to host element and set encapsulation to none. Then reference that class which was added to the host within the components style.css.scss This will allow us to declare styles which will only affect ourselves and our children within scope of our class. f.e.

@Component({
  selector: 'my-component',
  templateUrl: './my-component.page.html',
  styleUrls: ['./my-component.page.scss'],
  host: {
    class: 'my-component-class'
  },
  encapsulation: ViewEncapsulation.None
})

in combination with the following css (my-component.page.scss)

// refer ourselves so we are allowed to overwrite children but not global styles
.my-component-class {
  // will effect direct h1 nodes within template and all h1 elements within child components of the 
  h1 {
    color: red;
  }
}
// without class "scope" will affect all h1 elements globally
h1 {
  color: blue;
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Snackaholic
  • 590
  • 7
  • 27
2

The quick answer is you shouldn't be doing this, at all. It breaks component encapsulation and undermines the benefit you're getting from self-contained components. Consider passing a prop flag to the child component, it can then decide itself how to render differently or apply different CSS, if necessary.

<parent>
  <child [foo]="bar"></child>
</parent>

Angular is deprecating all ways of affecting child styles from parents.

https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep

Jed Richards
  • 12,244
  • 3
  • 24
  • 35
  • Well they've said explicitly in their docs they're doing it eventually, which I guess means they will. I agree though, not happening anytime soon. – Jed Richards Mar 01 '18 at 11:05
  • So they will pretty much make their own Materials library useless. I've never been able to use a default theme in any library since each customer require their own design. Usually you just want the functionality of a component. I can't say I understand their overall logic behind this decision. – Chrillewoodz Mar 01 '18 at 11:09
2

For assigning an element's class in a child component you can simply use an @Input string in the child's component and use it as an expression inside the template. Here is an example of something we did to change the icon and button type in a shared Bootstrap loading button component, without affecting how it was already used throughout the codebase:

app-loading-button.component.html (child)

<button class="btn {{additionalClasses}}">...</button>

app-loading-button.component.ts

@Input() additionalClasses: string;

parent.html

<app-loading-button additionalClasses="fa fa-download btn-secondary">...</app-loading-button>
deadflowers
  • 63
  • 1
  • 13
1

i also had this problem and didnt wanted to use deprecated solution so i ended up with:

in parrent

 <dynamic-table
  ContainerCustomStyle='width: 400px;'
  >
 </dynamic-Table>

child component

@Input() ContainerCustomStyle: string;

in child in html div

 <div class="container mat-elevation-z8"
 [style]='GetStyle(ContainerCustomStyle)' >

and in code

constructor(private sanitizer: DomSanitizer) {  }

  GetStyle(c) {
    if (isNullOrUndefined(c)) { return null; }
    return  this.sanitizer.bypassSecurityTrustStyle(c);
  }

works like expected and should not be deprecated ;)

d00lar
  • 802
  • 7
  • 25
  • Interesting! I ended up with something similar (for now). Where do you get DomSanitizer from? Edit: Found it: https://angular.io/api/platform-browser/DomSanitizer – Zaphoid Apr 23 '19 at 15:27
  • yep in v7 it is native you just have to request injection of it in constructor. ;) , in older i have no idea if it existed - i started from v7 ;) – d00lar Apr 24 '19 at 19:25
0

As the internet updates I've come across a solution.

First some caveats.

  1. Still don't do it. To clarify, I wouldn't plan on child components allowing you to style them. SOC. If you as the component designer want to allow this then all the more power to you.
  2. If your child doesn't live in the shadow dom then this won't work for you.
  3. If you have to support a browser that can't have a shadow dom then this also won't work for you.

First, mark your child component's encapsulation as shadow so it renders in the actual shadow dom. Second, add the part attribute to the element you wish to allow the parent to style. In your parent's component stylesheet you can use the ::part() method to access

Luminous
  • 1,771
  • 2
  • 24
  • 43
0

This is a solution with just vanilla css, nothing fancy, you don't even need !important. I assume you can't modify the child, otherwise the answer is even more simple, I put that answer at the end just in case.

Overriding a child's CSS is sometimes needed when using a pre-made component from a library, and the devs have not provided any class input variables. ::ng-deep is deprecated and encapsulation: ViewEncapsulation.None turns all of your component's CSS global. So here is a simple solution that uses neither of those.

The fact is, we do need a global style in order for the CSS to reach the child. So, we can just put the style in styles.css or we can create a new CSS file and add it to the styles array in angular.json. The only issue is that we need a specific selector so as not to target other elements. That's a pretty easy solution - just add a unique class name to the html, I recommend using the parent component's name in the class name to ensure it is unique.

Parent Component

<child class="child-in-parent-component"></child>

Let's pretend we want to change the background-color of all the buttons within the child, we do need to achieve the correct specificity to make sure our styles take precedence. We can do this with !important next to all our properties, but a better way is to just repeat the class name until our selector is specific enough, may take a few tries. That way, someone else can override this css again if necessary.

Global Styles File

.child-in-parent-component.child-in-parent-component.child-in-parent-component
  button {
  background-color: red;
}

or quick and dirty with !important (not recommended)

.child-in-parent-component button {
  background-color: red !important;
}

If the child component can be modified

Simply add an input variable to the component and make use of Angular's ngStyle directive. You can add multiple variables to style multiple areas of your component.

Child Component

type klass = { [prop: string]: any } | null;

@Component({...})
export class ChildComponent {
  @Input() containerClass: klass = null;
  @Input() pClass: klass = null;
...
}
<div [ngStyle]="containerClass">
  <p [ngStyle]="pClass">What color will I be?</p>
</div>

Parent Component

<child
  [containerClass]="{ padding: '20px', 'background-color': 'black' }"
  [pClass]="{ color: 'red' }"
>
</child>

This is the intended way to create a component with a dynamic style. Many pre-made components will have a similar input variable.

Chris Hamilton
  • 9,252
  • 1
  • 9
  • 26
  • take a look also the solution proposed by [Vivanov](https://stackoverflow.com/questions/36527605/how-to-style-child-components-from-parent-components-css-file/62093818#62093818) in this threat – Eliseo Mar 17 '22 at 08:06
  • @Eliseo that's not applicable if you are using a component from a library. If you have access to the source code you can just use an input variable coupled with the `ngStyle` directive. https://angular.io/api/common/NgStyle – Chris Hamilton Mar 17 '22 at 08:21
  • @Eliseo I edited my answer to show you what I mean. – Chris Hamilton Mar 17 '22 at 08:43
0

this has worked for me

in the parent component:

<child-component [styles]="{width: '160px', borderRadius: '16px'}" >
</child-component>
sean717
  • 11,759
  • 20
  • 66
  • 90
-1

I propose an example to make it more clear, since angular.io/guide/component-styles states:

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.

On app.component.scss, import your *.scss if needed. _colors.scss has some common color values:

$button_ripple_red: #A41E34;
$button_ripple_white_text: #FFF;

Apply a rule to all components

All the buttons having btn-red class will be styled.

@import `./theme/sass/_colors`;

// red background and white text
:host /deep/ button.red-btn {
    color: $button_ripple_white_text;
    background: $button_ripple_red;
}

Apply a rule to a single component

All the buttons having btn-red class on app-login component will be styled.

@import `./theme/sass/_colors`;

/deep/ app-login button.red-btn {
    color: $button_ripple_white_text;
    background: $button_ripple_red;
}
AndreaM16
  • 3,917
  • 4
  • 35
  • 74
-2

I have solved it outside Angular. I have defined a shared scss that I'm importing to my children.

shared.scss

%cell {
  color: #333333;
  background: #eee;
  font-size: 13px;
  font-weight: 600;
}

child.scss

@import 'styles.scss';
.cell {
  @extend %cell;
}

My proposed approach is a way how to solve the problem the OP has asked about. As mentioned at multiple occasions, ::ng-deep, :ng-host will get depreciated and disabling encapsulation is just too much of a code leakage, in my view.

E_net4
  • 27,810
  • 13
  • 101
  • 139
Jakub
  • 479
  • 5
  • 17
-3

let 'parent' be the class-name of parent and 'child' be the class-name of child

.parent .child{
//css definition for child inside parent components
} 

you can use this format to define CSS format to 'child' component inside the 'parent'