Angular: override child components without ng-deep

Assume you want to modify styles of child components but

✅ You want clean and native approach so you don’t want to use ng-deep

✅ You want to avoid host-selector ensuring that your child component styles remain unbloated.

💎 Live Demo: https://stackblitz.com/edit/stackblitz-starters-lvddww

The Objective:

Let’s consider a practical scenario: we have a post-card component that we want to style. Here’s what the current HTML and SCSS structure looks like:

Post Card Component
Post Card Component

The HTML structure:

<div class="post">
  <h3 class="post__title">{{ title }}</h3>
  <button class="post__btn">
    <a [href]="link"> Read More</a>
  </button>
</div>

The SCSS structure:

:host {
  display: block;
}

.post {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 600px;
  box-shadow: 0px 1px 7px rgb(34 35 58 / 20%);
  background: #fff;

  &__title {
    padding: 10px;
    font-size: 1.8rem;
    font-weight: 600;
    margin: 0px;
    color: #000;
  }

  &__btn {
    background: #f1c40f;
    border-radius: 4px;
    border: 0;
    padding: 0 16px 0 16px;
    height: 36px;
    margin-left: 10px;
    cursor: pointer;
    a {
      text-decoration: none;
    }
  }
}

We want to transfer post-card styles to look like below:

Post Card new styles
Post Card new styles

Solution 🚀:

Our aim is to transform the style of the post-card component to resemble the above design. But instead of hard coding the styles of the nested components, we’ll use CSS variables, allowing us to manipulate these variables from the parent component.

Here’s the new and improved SCSS structure of post-card:

:host {
  display: block;
}

.post {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 600px;
  box-shadow: 0px 1px 7px rgb(34 35 58 / 20%);
  background: var(--post-card-background, #fff);

  &__title {
    padding: 10px;
    font-size: var(--post-card-title-font-size, 1.8rem);
    font-weight: 600;
    margin: 0px;
    color: var(--post-card-title-color, #000);
  }

  &__btn {
    background: var(--post-card-btn-background, #f1c40f);
    border-radius: 4px;
    border: 0;
    padding: 0 16px 0 16px;
    height: 36px;
    margin-left: 10px;
    cursor: pointer;
    a {
      text-decoration: none;
    }
  }
}

So let’s explain a bit further.

background: var(--post-card-background, #fff);

This above code says: Use var( — post-card-background) as a background color but IF that css variable does not exist use default fallback (#fff) 😎.

Now in ANY parent component we can override those css variables. So in our parent post-list component.

.post-card {
  --post-card-btn-background: #27ae60;
  --post-card-background: #34495e;
  --post-card-title-color: #fff;
}

and HTML structure:

<div class="post-list">
  <post-card class="post-card"/>
</div>

That’s all. I tried to keep it short. Hope you find it useful 🙂.

💎 Source Code: https://stackblitz.com/edit/stackblitz-starters-lvddww

About me: I am a junior front-end developer.

Twitter: https://twitter.com/Vugar005