10

What i have understood of host is that if i have a child component inside a parent component and we want to style a child component from the parent component we can use :host . and :host-context for vice-versa. Please let me know if this is the right use of host .

https://angular.io/docs/ts/latest/guide/component-styles.html

When i try to do the same in my App it dosent work

App component template

  <div class ="top">
    <h1>
      Home Component
    </h1>
    <hr>
    <app-ngrx></app-ngrx>
    <router-outlet></router-outlet>
  <div>

ngrx component template

  <h3 class="mine">NGRX</h3>

<button (click)="increment()">Increment</button>
<div>Current Count: {{ counter | async }}</div>
<button (click)="decrement()">Decrement</button>

<button (click)="reset()">Reset Counter</button>

App component CSS

:host(.mine){
  color:red;
}

This do not Seem to work Please help i am not able to understand.

I looked at this question But just not able to figure out

Angular 2: How to style host element of the component?

Updated after @Gunter Answer

In my app-ngrx template i have added

  <h3 class = "mine">NGRX</h3>

<button (click)="increment()">Increment</button>
<div>Current Count: {{ counter | async }}</div>
<button (click)="decrement()">Decrement</button>

<button (click)="reset()">Reset Counter</button>

and in the app-ngrx css file i have added

:host(.mine){
  color:red;
}

But even without adding mine in app component like

<app-ngrx></app-ngrx>

The h3 is red where as i feel it should be red when <app-ngrx class = "mine"></app-ngrx>

Community
  • 1
  • 1
  • I don't understand your update. `

    ` won't be affected. The whole `` should be `red`. (`` should not be red, because `red` is the wrong class - you probably meant to use `class="mine"`)

    – Günter Zöchbauer Mar 03 '17 at 17:05
  • @GünterZöchbauer ya class mine , i only want the h3 of the component to be red instead of the whole template to be shown red –  Mar 03 '17 at 17:08
  • Then don't use `:host` – Günter Zöchbauer Mar 03 '17 at 17:08
  • if i just want the h3 of the ngrx to be updated from the parent not the whole template as people will want to change button color or add some class based on some value of the parent component class –  Mar 03 '17 at 17:09
  • @GünterZöchbauer without host how we acheive this from parent component i am so confused now –  Mar 03 '17 at 17:10
  • No, without `:host` you select the content of the current component. Of course if you have `` in the template of the component and you add style `my-child { color: red; }` then seen from `` it's styled from the parent, but if you see it from the component where you add the style, then you style its content. – Günter Zöchbauer Mar 03 '17 at 17:13
  • So in order to style only h3 of child component we have to do that in the child component css right we cannot from the parent component css –  Mar 03 '17 at 17:17
  • If you want to style `

    ` **inside** a child component you use `:host /deep/ h3 {color: red;}`.

    – Günter Zöchbauer Mar 03 '17 at 17:40

2 Answers2

27

What i have understood of host is that if i have a child component inside a parent component and we want to style a child component from the parent component we can use :host . and :host-context for vice-versa

No, this is not what it used for.

:host selector comes from shadow DOM spec.

...This scoped subtree is called a shadow tree. The element it's attached to is its shadow host.

In angular world, a component's template is a shadow tree. The component's element is a shadow host. So when you're defining styles for :host selector, the styles are applied to the component's element.

:host

In your example, if you defined styles in my-app component, the styles will be applied to <my-app> DOM element. This particular configuration:

:host(.mine){
  color:red;
}

Will be applied to the host element that has .mine class:

<my-app class="active">

If you defined styles in app-ngrx component, the styles will be applied to <app-ngrx> DOM element, NOT <my-app>. This particular configuration:

:host(.mine){
  color:red;
}

Will be applied to the host element that has .mine class:

<app-ngrx class="active">

:host-context

Now, :host-context is also applied to the host element, but the function (parenthesis) takes a selector that is checked not against the host element itself, but against all ancestors up to document root. If such element is found, the styles are applied.

For example, this selector

:host(.mine){
  color:red;
}

matches such structure:

<my-app class="mine">

whereas, this selector:

:host-context(.mine){
  color:red;
}

matches this structure:

<div class="mine">
 ...
   <my-app>

This is useful, if you want to apply styles to components view (shadow root) conditionally. This makes h2 always bold:

h2 {
   font-weight: bold;
}

whereas this

:host-context(.make-inner-components-bold) h2 {
  font-weight: bold;
}

makes them bold only if your component is inside an element with class .make-inner-components-bold.

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
21
  • :host { ... } selects the component itself
  • :host(.mine) { ... } selects the component itself when it has class="mine" set

  • :host-context(.mine) { ... } selects the component itself when one of its ancestors has class="mine" set

See also https://angular.io/docs/ts/latest/guide/component-styles.html

@Component({
  selector: 'h3', 
  styles: [':host(.mine) { color: red; }], 
  template: '<ng-content></ng-content>'}) 
class MyH3Component{}
<h3 class="mine">this is red</h3>
<h3>this is black</h3>

or with :host-context

@Component({
  selector: 'h3', 
  styles: [':host-context(.mine) { color: red; }], 
  template: '<ng-content></ng-content>'}) 
class MyH3Component{}

<body class="mine">
  <my-app><my-app>
<body>

AppComponent

template: '<h3>this is red</h3>'

or with class="mine" set

<body>
  <my-app><my-app>
<body>

AppComponent

template: '<h3>this is black</h3>'

update

If you want to style the content of a child component (instead of the child component itself) you can use /deep/

:host child /deep/ h3 {
  color: red;
}

update 2 ::slotted is now supported by all new browsers and can be used with `ViewEncapsulation.ShadowDom

https://developer.mozilla.org/en-US/docs/Web/CSS/::slotted

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • So it is like not to modify css but just to select the component based on that selector –  Mar 03 '17 at 16:19
  • so if i remove class mine from ngrx template it wont be selected , i am really confused with this concept –  Mar 03 '17 at 16:20
  • If you had a component with `@Component({selector: 'h3', styles: [':host(.mine) { color: red; }], template: ''}) class MyH3Component{}`, then adding or removing `class="mine"` from `

    ` will switch the color of `

    ` between `red` or `default`.

    – Günter Zöchbauer Mar 03 '17 at 16:23
  • then adding and removing a class from a different component right ? –  Mar 03 '17 at 16:34
  • Sorry, don't understand your comment. – Günter Zöchbauer Mar 03 '17 at 16:34
  • you mentioned right then adding or removing class ="mine" from h3 how do we acheive that from the main app component, i guess i am asking a lot but if you can provide a plunker it will be great –  Mar 03 '17 at 16:36
  • I updated my answer. I hope this makes it more clear – Günter Zöchbauer Mar 03 '17 at 16:36
  • Yup thanks but this can be acheived by using normal ement selector like h3{color:red} –  Mar 03 '17 at 16:38
  • But for this you need to add the style to the parent component. If you want your component to style itself from the inside, you need `:host()` or `:host-context()` - In my example I made `

    ` an Angular component, because you added `class="mine"` to this element.

    – Günter Zöchbauer Mar 03 '17 at 16:41
  • Yes now i get it , if i want to target a particular element in that component how do we acheive that beacuse as of now all the elements have color red –  Mar 03 '17 at 16:43
  • Sorry, forgot to edit the last example where `` doesn't have `class="mine"`. Is this what you were referring to? – Günter Zöchbauer Mar 03 '17 at 16:45
  • i am refer to like if my components have multiple elements i only want to add style to a particular element using host how to do that –  Mar 03 '17 at 16:48
  • Then you don't need `:host`. You can just use `styles: ['div.mine { color: red; }'], template: '
    this is red
    this is black
    '`
    – Günter Zöchbauer Mar 03 '17 at 16:50
  • You can use host as parent selector like `:host > div.mine` to only select `
    ` which are top-level elements inside the component.
    – Günter Zöchbauer Mar 03 '17 at 16:51
  • i have updated the question a bit please check after @Gunter answer in the question, i am really confused sorry –  Mar 03 '17 at 17:02
  • @INFOSYS, did you get a chance to see my answer? Is your question still about two components or is it about one component? – Max Koretskyi Mar 03 '17 at 17:39
  • @Maximus i did see your answer and it cleared the misconception about host and host context thanks, –  Mar 03 '17 at 17:45
  • @INFOSYS, so do you still have a question? – Max Koretskyi Mar 03 '17 at 17:48
  • @Maximus Yes a last doubt what is the difference between host and host-context as now when i am trying examples both see, to do the same thing –  Mar 03 '17 at 17:50
  • @INFOSYS, I've updated my answer. Check if it's clear now – Max Koretskyi Mar 03 '17 at 18:02
  • @Maximus yes thanks great this is i just figured out in the angular docs –  Mar 03 '17 at 18:17
  • @INFOSYS, sure, you're welcome. Yeah, this is sometimes a dilemma for me as well which answer to accept :). – Max Koretskyi Mar 03 '17 at 18:19