Angular ngClass and ngStyle: The Complete......

Angular ngClass and ngStyle: The Complete Guide

Angular ngClass and ngStyle: The Complete Guide

Component Styling using ngClass - when to use it?

Most of the styles that we need to apply are always present, and can be simply be applied as standard HTML in our templates, like this:


<p>A Bootstrap Primary Button:</p>
<button class="btn btn-primary">Button</button>          


But there are often styles that are applied conditionally to our templates - they are added to an element only if a certain programmatic condition is met.


This is, for example, the case of state styles (if we adopt the SMACSS terminology).


For these cases, is ngClass needed?

Note that many state styles can be natively implemented using browser CSS pseudo-classes, such as for example:

  • styles for identifying an element with the focus, via the :focus pseudo class
  • hover styles and on-click active state styles (using :hover and :active)


For these type of state styles natively supported by the browser, it's better to use the CSS pseudo classes whenever possible. So for these very common cases we won't need ngClass.


Some good examples for the use of ngClass


But there are many other state styles that are not natively supported by the browser. These styles could for example include:

  • styles for identifying the currently selected elements of a list
  • styles for identifying the currently active menu entry in a navigation menu
  • styles to identify a certain feature of a element; for example to identify a new element in an e-commerce site


If the element that we are styling only has one of those state styles, we can even apply it simply by using the plain input property template syntax, without any extra directive:


<p>Default Button:</p>
<button class="btn btn-primary" type="submit">Button</button>
<p>Equivalent example using Button:</p>
<button class="btn" [class.btn-primary]="true" type="submit">Button</button>


Notice the syntax [class.btn-primary] that is activating the btn-primary CSS class, effectively adding it to the button.


This expression will add or not the class to the element depending on the truthiness of the expression, which in this case is always true.


But more often than not, an element ends up having multiple state styles, and that is when the ngClass directive comes in handy!

The ngClass directive will take an expression that will be used to determine which state styles to apply at a given time to the styled element.

The expression passed on to ngClass can be:

  • an object
  • an array
  • a string


Let's go over each one of these 3 cases with examples, and then see how we can make sure that we can still keep our templates light and readable.


Passing an Array of CSS classes to ngClass

One way of defining what classes should be active at a given moment is to pass an array of strings to the ngClass directive.

For example, the following expression contains an array of classes:


<p>Passing an Array of classes:</p>
<button [ngClass]="['btn', 'btn-primary']">Button</button>


Angular will then take the array passed to ngClass, and apply the CSS classes that it contains to the HTML button element. This is the resulting HTML:

<button class="btn btn-primary">Button</button>


Notice that the CSS classes don't have to be hard-coded in the template using this syntax (its just an example), more on this later.

Passing a String of CSS classes to ngClass

Its also possible to pass to ngClass a string, that contains all the CSS classes that we want to apply to a given element:


<p>Passing a string:</p>
<button [ngClass]="'btn btn-primary'" type="submit" (click)="submit()">Button</button>


This syntax would give the same results as before, meaning that the two CSS classes btn and btn-primary would still be applied.


Passing a configuration object to ngClass

The last and most commonly used way that we can configure ngClass is by passing it an object:

  • the keys of that object are the names of the CSS classes that we want to apply (or not)
  • and the values of the configuration object should be booleans (or an expression that evaluates to a boolean) that indicate if the CSS class should be applied


Let's have a look at an example of how to use this syntax:

<p>Passing a configuration object:</p><button [ngClass]="{ btn:true, 'btn-primary':true }">  Button</button>


This example would give the same results as before: the two CSS classes would still get applied.

But if for example start using longer expressions to calculate our boolean values, or have several state classes, this syntax could quickly become hard to read, overloading the template and putting too much logic in it.

Let's then see what we can if we run into that case!


Delegating to the component which styles should be applied

One of the roles of the component class is to:

  • coordinate the link between the View definition (the template), and the data passed to the component (the Model)
  • as well as to keep track of any other type of visual component state that is tied uniquely to the component and is transient in nature (like a flag saying if a collapsible panel is open or not)

If our ngClass expressions start to get too cumbersome and hard to read, what we can do is pass to ngClass the output of a component method:


@Component({selector: 'app-root',template: `<button (click)="toggleState()">Toggle State</button>     
   <p>Obtaining the CSS classes from the component method:</p>    
    <button [ngClass]="calculateClasses()" (click)="submit()">Button</button> `})export class AppComponent {
    stateFlag = false;
    toggleState() {this.stateFlag = !this.stateFlag;    }
    submit() {console.log('Button submitted');    }
    calculateClasses() {   
     return {btn: true, 'btn-primary': true, 'btn-extra-class': this.stateFlag };  
  }}


Notice that we could pass parameters to this method if needed. Let's then break down what is going on in this example:

  • The component now has a member variable stateFlag, which will identify if a given component state is active or not.
  • This could also have been an enum, or a calculation derived from the input data
  • The method calculateClasses will now return a configuration object equivalent to the one we just saw above
  • the CSS class btn-extra-class will be added or not to the HTML button depending on the value of the stateFlag variable


But this time around the calculation of the configuration object is done in a component method, and the template becomes a bit more readable.

This function could have also returned an array or string containing multiple CSS classes, and the example would still work!

As we can see, between the native browser functionality and ngClass, we will be able to do most of the styling for our components.

But are there use cases where we would like to apply styles directly to an element?


How to use ngStyle to add embedded styles to our templates

Just like in the case of plain CSS, sometimes there are valid use cases for applying directly styles to an HTML element, although in general this is to be avoided.

This is because this type of embedded styles takes precedence over any CSS styles except styles that are marked with !important.

To give an example of when we would like to use this: Imagine a color picker element, that sets the color of a sample rectangle based on a handle that gets dragged by the user.

The varying color of the element needs an embedded HTML style, as its not known upfront. If we run into such an use case using Angular, we can implement it using the ngStyle built-in core directive:

<p>Passing an object to ngStyle:</p><button [ngStyle]="{background: 'red'}">Button</button>


And this would be the resulting HTML:


<button style="background: red">Button</button>


Just like the case of ngClass, if our ngStyle expression starts to get too large, we can always call a component method to calculate the configuration object:

<p>Obtaining styles from a component method:</p><button [ngStyle]="calculateStyles()">Button</button>   


And with this, we can now add both CSS classes and embedded styles conditionally to our components!


Share Article:
  • Facebook
  • Instagram
  • LinkedIn
  • Twitter
  • Recent Posts