How to theme styles with Angular and SASS

With so many components and pieces of code in an angular application, CSS, cascade styling, may not be so straightforward as styles may be loaded in different orders or affect other components when you less expect it. Though after 15+ years styling websites, I was more than used to organise my styles in a proper way to have everything working nicely. Or maybe I never had such a big website on my hands for this to be an issue. But now that styles are encapsulated in the component when you give it some, while very useful to specify local styling (which still inherits the global) it can become painful to then maintain some sense of cascading, like how to reference a style in the parent to determine your child’s one.

Why would I want to do that?

Well, let’s call it theming. I happen to need to adapt the styles depending on a class added to a tag at the top of the page with the name of the theme.

Using SASS

If you are using SASS and you are adding this to the global styles (encapsulation only happens at the Angular components, so global styles aren’t affected by it) you can always do this trick to set themed styles:

.some-div {
// Default
background: black;

body.red-theme & {
background: red;
}
body.blue-theme & {
background: blue;
}
body.green-theme & {
background: green;
}
}

Using Angular pseudo classes

First of, we can use :host to reference the component tag, which can be useful to set styles on such element already:

:host {
background: black; // The entire component will have this background
}

But for our theming purposes, we can use the :host to check if certain classes have been added to it from the outside by doing this:

:host(.theme-blue) {
button {
background: blue;
}
}
:host(.theme-red) {
button {
background: red;
}
}

Also adding SASS to that you can get this:

button {
:host(.theme-blue) & {
background: blue;
}
:host(.theme-red) & {
background: red;
}
}

But having to add such classes to our components one by one wouldn’t be pragmatic, so instead we can use :host-context to check around the component parents if our component has a certain context, also combining this with SASS:

.some-div-inside-angular-component {
// Default
background: black;

:host-context(body.red-theme) & {
background: red;
}
:host-context(body.blue-theme) & {
background: blue;
}
:host-context(body.green-theme) & {
background: green;
}
}

And that works.

Just note that the :host-context pseudo-class only works inside an Angular component, so don’t try to use it at the global styles.

More about this at component styles, angular host context and sass parent selector.