Style Child components from Parent – Angular

By default, Angular styles are restricted within each component, preventing the inheritance of styles from the parent component to its child. However, fear not! There exist numerous methods to overcome this limitation. Brace yourself as we dive into the depths of this blog to uncover the truth: Is it truly essential to style child components from the parent? And if it is, we shall delve into the finest strategies to achieve this feat.

The Scenario

In this scenario, we encounter a parent component, known as the app component, that encompasses a child component, namely the user component.

app.component.html
<div class="user-container>
    <app-user [userName]="userName"></app-user>
</div>
user.component.ts
@Component({
   selector: "app-user",
   templateUrl: "./user.component.html",
   styleUrls: ["./user.component.scss"],
})
export class UserComponent {
    @Input() userName: string;
}
user.component.html
<div class="user-details>
    Hi {{userName}}!
</div>
user.component.scss
.user-details{
    height: 50px;
    width: 50px;
    border: 1px solid #e4e4e4;
    border-radius: 5px;
}

In the given scenario, the user component functions as a child component, with the name serving as the input parameter. It is worth examining the scss (user.component.scss) closely, as it explicitly defines the border and border-radius properties for the user-details class within the child component. These specified styles will be applied when the component is rendered.

How can we add background color from parent component?

There are two ways through which you can confidently change the style of a child component from its parent.

  • ViewEncapsulation.None
  • ::ng-deep

ViewEncapsulation.None

Alright, let me break it down for you. ViewEncapsulation is like creating a protective shield around your component’s style. It’s as if you’re putting it in a little bubble, ensuring that it doesn’t interfere with any other part of the application. This way, you can maintain your stylish edge without causing any unexpected disruptions. Pretty cool, right?

app.component.scss
.user-details {
   background-color: #ff0000
}

On the above code, we have mentioned the background-color of the child element (.user-details). But, wait? Will it be applied to the child component? No because, the styles mentioned in app component is encapsulated only to that respective component. To break that, we need to mention `ViewEncapsulation.None in the app component.

app.component.ts
import { ViewEncapsulation } from "@angular/core";
@Component({
   selector: "app-main",
   templateUrl: "./app.component.html",
   styleUrls: ["./app.component.scss"],
   encapsulation: ViewEncapsulation.None // This line does the magic for you
})
export class AppComponent {
}

Now if you run the application, the background color style will be applied to the child component. But let’s say if another component in the application has the same class name(.user-details) the background-color will be applied to those componentsas as well. So, you should be very careful on using it. And also it’s not a good practice to use ViewEncapsulation.None.

::ng-deep

::ng-deep is a css selector where it can shadow-pierce the DOM elements and apply the styles.

app.component.scss
::ng-deep .user-details {
   background-color: #ff0000
}

On applying ::ng-deep, the style will be applied to the child component. But it also has the same disadvantage as ViewEncapsulation.None. The style will be treated as a global one and it will be affected to other components which has the same class name(user-details).

So instead of exposing this style globally, you can use :host css selector where the style will be scoped only to that respective component and its descendants.

app.comopnent.scss
:host ::ng-deep user-details {
    background-color: #ff0000
}

Now the style will be scoped only to app component and it’s child components

From Angular12, ::ng-deep is deprecated. So, in future it may be removed from Angular. Use it when it’s really necessary.

What’s the best solution?

The above two methods have its own set of challenges. And also it’s not a good practice to overwrite the child component scss from parent component. All the styles of child components will be scattered in different components.

Usually, a component should be an independent entity where it has its own set of styles and functionalities. So, the best solution would be having all set of styles in the child component and create a way of triggering it from the parent component. So how can we do it?

  • :host
  • Host-Binding

:host

In child component, you can define different background colours based upon your need using the :host selector.

user.component.scss
:host {
  .bg-none {
    background-color: none;
  }
  .bg-danger {
    background-color: #ff0000;
  }
}

And from your parent component you can mention the host element scss using the class attribute.

app.component.html
<div class="user-container>
    <app-user class="bg-danger"
              [userName]="userName"></app-user>
</div>

Host Binding

Host Binding allows us to set property to the respective host elements.

By the combination of @Input() and @HostBinding() we should be able to achieve this in a better way.

user.component.ts
@Component({
   selector: "app-user",
   templateUrl: "./user.component.html",
   styleUrls: ["./user.component.scss"],
})
export class UserComponent {
    @Input() userName: string;
    @Input() @HostBinding("class.bg-danger") isDanger = false;
}
app.component.html
<div class="user-container>
    <app-user [isDanger]="true"
              [userName]="userName"></app-user>
</div>

As you can see, having an input parameter makes it less error prone. It’s not necessary to remember the class name, instead it’s just sending an input to the child component.

Conclusion

Is it really necessary to style a child component from its parent?

As I said before, a component should be its own thing. If you find yourself in a situation where you need to style a child component from the parent, just put the styles in the child and figure out how to make it happen from the parent.

So that the different styles of the child component won’t be spread all over the app.

One thought on “Style Child components from Parent – Angular

Add yours

  1. I don’t see how the reasoning that “each child should be it’s own thing” is compellable when we style every component else that is not a custom angular component (and most libraries provide ways to customize them). CSS was literally designed for people to be able to change the styles of internal things, and it appeas that for many things (like creating a custom ‘row’ component or ‘column’ where custom styling would be great [like for setting the justify-content] this belief is rather lacking).

    What do you think about it?

    Like

Leave a reply to nipah~☆! Cancel reply

Blog at WordPress.com.

Up ↑