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

Contents are based on Angular version 2+.

Table of contents

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.background-image]="getProfilePicStyle()">
    </div>
  `
})
export class App {
  
  getProfilePicStyle() {
    // snip snip -> fetch the url from somewhere
    const profilePicUrl = 'some-remote-server-url.jpg';
    return `url(${profilePicUrl}`;
  }
  
}

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) {}

  getProfilePicStyle() {
    // snip snip -> fetch the url from somewhere
    const profilePicUrl = 'some-remote-server-url.jpg';

    // sanitize the style expression
    return this.sanitizer.bypassSecurityTrustStyle(`url(${profilePicUrl}`);
  }
  
}

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() {
  }
  
}

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 2 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.

Conclusion

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

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


Further reading

Angular 2 components are not just like plain Angular 1 directives with a different syntax. There’s much more. They give you true encapsulation at the CSS as well as JavaScript level, just like web components do. Components have an encapsulation property which expects either

By default it emulates, but if you set it to ViewEncapsulation.Native you’ll get native shadow DOM support. Check out @toddmotto’s article on Emulated or Native Shadow DOM in Angular 2 with ViewEncapsulation for an in depth guide on this :thumbsup:.


If you enjoyed this post you might want to follow me on Twitter for more news around JavaScript and Angular. :smiley: