Here we're going through a couple of ways to conditionally apply some styles to a DOM element in Angular.

Contents are based on Angular version 2+.

Table of contents

Egghead.io Course: Understand How to Style Angular Components

Check out my Egghead.io course to get a full picture on styling Angular components. I hope you enjoy it :blush:

Directly manipulating styles property

A rather unconventional way would be to return the styling property as a string and then to directly set it on the desired element:

//our root app component
import {Component} from [email protected]/core'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <div [style.background-color]="getStyle()">
        I am a div that wants to be styled
      </div>
      <button (click)="showStyle = !showStyle;">Toggle style</button>
    </div>
  `
})
export class App {
  showStyle: false;
  
  constructor() {
  }
  
  getStyle() {
    if(this.showStyle) {
      return "yellow";
    } else {
      return "";
    }
  }
}

Note the [style.background-color] in the code above.

Style Sanitization

Assume for instance we want to dynamically add a background image of a user’s profile image, using the [style.background-image]="..." approach. Naively, we may try the following:

@Component({
  selector: 'my-app',
  template: `
    <div [style]="getStyle()">
    </div>
  `
})
export class App {
  
  getStyle() {
    // snip snip -> fetch the url from somewhere
    const profilePicUrl = 'some-remote-server-url.jpg';
    const style = `background-image: url(${profilePicUrl})`;
    return style;
  }
  
}

However, what we get is an error message from Angular saying:

WARNING: sanitizing unsafe style value url…

This is a security warning, alerting us for a potential XSS security vulnerability. If you know that the URL is safe, you can go around this and mark the style as safe.

import { DomSanitizer  } from [email protected]/platform-browser';

@Component({...})
export class App {
  
  constructor(private sanitizer: DomSanitizer) {}

  getStyle() {
    // snip snip -> fetch the url from somewhere
    const profilePicUrl = 'some-remote-server-url.jpg';
    const style = `background-image: url(${profilePicUrl})`;

    // sanitize the style expression
    return this.sanitizer.bypassSecurityTrustStyle(style);
  }
  
}

The DomSanitizer has other methods as well: refer to the official docs.

The good old “ngClass”

Straight away, there’s still the good old NgClass which might especially be known by Angular 1 developers. NgClass allows to pass in an object (key:value) where the key represents the class and the value a boolean condition which controls whether that specific class is applied to the element or not.
That said, it is the preferred way of adding one or more classes to an element.

It is made available under the @angular/common module which is imported already for you (under the @angular/browser module), so there’s no need to do it manually. Then we can use it just as we did in Angular 1. Here’s the full code example.

//our root app component
import {Component} from [email protected]/core';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <div [ngClass]="{'my-class': isClassVisible }">
        I am a div that wants to be styled
      </div>
      <button (click)="isClassVisible = !isClassVisible;">Toggle style</button>
    </div>
  `,
  styles: [
  `
  .my-class {
    background-color: yellow;
  }
  `
  ]
})
export class App {
  isClassVisible: false;
  
  constructor() {
  }
  
}

Adding a single class

An alternative to the ngClass and especially in situations when only a single class needs to be applied is the following syntax.
Similarly as we did with the background-color above, we can add a single class, using the following notation: [class.nameOfClass]="someCondition".

//our root app component
import {Component} from [email protected]/core'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <div [class.my-class]="isClassVisible">
        I am a div that wants to be styled
      </div>
      <button (click)="isClassVisible = !isClassVisible;">Toggle style</button>
    </div>
  `,
  styles: [
  `
  .my-class {
    background-color: yellow;
  }
  `
  ]
})
export class App {
  isClassVisible: false;
  
  constructor() {
  }
  
}

Using :host(..) and @HostBinding

Consider you have a component <styled> which you’d like have different CSS classes applied based on some setting, like .yellow-style in case when you specify <styled style="yellow"> and .red-style when you pass in red: <styled style="red">.

What’s important to note here is that, different to what we did so far, we don’t want the CSS class to be applied on some element that’s internal to our component, but onto the component itself. Example:

<styled style="red" _nghost-c0="" ng-reflect-style="red" class="red-style">
    <div _ngcontent-c0="">
      I'm a div that wants to be styled
    </div>
</styled>

Still, for reusability purposes, our styles should be supplied with the component itself, so again we use the styles property of our StyledComponent:

@Component({
  selector: 'styled',
  template: `
    <div>
      I'm a div that wants to be styled
    </div>
  `,
  styles: [
    `
      :host(.yellow-style) {
        background-color: yellow;
        border: 1px solid black;
        display:block;
      }
      
      :host(.red-style) {
        background-color: red;
        border: 1px solid black;
        color: white;
        display:block;
      }
    `
  ]
})
export class StyledComponent { }

As you can see, we use the special :host(...) selector to target the styles on the element that hosts the component. More info on the official docs about this. In this way .yellow-style as well as .red-style will be visible at the host component level while they’d be otherwise encapsulated and only applicable to elements within our StyledComponent.

Next, we define an @Input() property which allows us pass in the style configuration.

@Component({...})
export class StyledComponent {
    @Input() style;
}

What we’re still missing is to programmatically set the CSS class on our host element based on the value of the style input property. We use the @HostBinding for this:

import { Component, Input, HostBinding } from [email protected]/core';

@Component({ ... })
export class StyledComponent {
  @Input() style;
  
  @HostBinding('class.yellow-style') yellowStyle:boolean = false;
  @HostBinding('class.red-style') redStyle:boolean = false;
  
  ngOnChanges(changes) {
    let newStyle = changes.style.currentValue;
    
    if(newStyle === 'yellow') {
      this.yellowStyle = true;
      this.redStyle = false;
    } else if(newStyle === 'red') {
      this.yellowStyle = false;
      this.redStyle = true;
    } else {
      // nothing here.. (fallback?)
    }
  }
}

In the ngOnChanges we the style input property changes, we properly adjust our style flags. (Note this is by far not the most intelligent code, but it’s simple enough so you get the idea :wink:).

Here’s an example to play around with.

Referencing the DOM element directly via ElementRef

The last possibility is by directly interacting with the underlying DOM element. For that purpose we create a directive styled which we add to our div.

<div styled>
    I'm a div that wants to be styled
</div>

Our directive looks like this:

import {Directive, ElementRef, Renderer} from [email protected]/core';

@Directive({
  selector: '[styled]',
})
export class StyledDirective {
  constructor(public el: ElementRef, public renderer: Renderer) {
    // el.nativeElement.style.backgroundColor = 'yellow';
    renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'yellow');
  }
}

The important part here is the ElementRef and the Renderer which I import in the constructor.

The ElementRef allows us to gain access to the nativeElement API via

el.nativeElement.style.backgroundColor = 'yellow';

This way you can deliberately modify the properties of the native DOM element. So why would I want to use the Renderer. Well, Angular isn’t only build for the browser, but it can potentially also be rendered on the server or render native elements on a mobile device (via NativeScript for instance). Thus, the Renderer provides an abstraction over the native elements.

Check out this Plunk for the full code.

More…

There’s more about styling such as style encapsulation, ngStyle, …. Learn about it with my 10 lessons Egghead.io course about “Understand How to Style Angular Components”.

Conclusion

So in this article you learned about 5 possibilities to style your DOM elements from within Angular. You got to see

You even quickly saw how to create a Directive and how to embed styles within a Component :smiley:.


If you enjoyed this post you might want to follow me on Twitter for more news around JavaScript and Angular or watch my Egghead.io video lessons. :smiley: