In this post, we are going to learn the most commonly used options that we have available for styling our Angular components using the ngClass and ngStyle core directives.
This is the first post of a two-part series in Angular Component Styling, if you are looking to learn about Angular style isolation and the Emulated View Encapsulation mode (which Angular uses by default), have a look at part two:
Angular :host, :host-context, ::ng-deep - The Complete Guide.
This post will cover the following topics:
- Component Styling using
ngClass
- when to use it and when to use other alternatives? ngClass
support for Arrays, strings of classes, configuration objectsngClass
support for component functionsngStyle
features- Summary
In order to cover each feature, we will be adding the multiple examples to this small Angular CLI sample application, that will use as external styles a Bootstrap default theme.
So without further ado, let's get started with ngClass
and all the multiple ways that we have for using it!
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:
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:
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:
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:
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:
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:
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:
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 thestateFlag
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:
And this would be the resulting HTML:
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:
And with this, we can now add both CSS classes and embedded styles conditionally to our components!
But another key feature of Angular that we have not covered yet, is the ability to isolate a component style so that it does not interfere with other elements on the page, and that is what we will be covering on part two of this series:
Angular :host, :host-context, ::ng-deep - The Complete Guide.
Summary
There are a ton of options to style our components using ngClass and ngStyle, so it's important to know which one to use when and why. Here is a short summary:
- most styles can be added simply to the HTML directly, for those we can simply add them to the class property, and no special Angular functionality is needed
- Many state styles can be used using browser-supported pseudo-class selectors such as
:focus
, we should prefer those conventional solutions for those cases - for state styles that don't have a pseudo-class selector linked to it, its best to go with
ngClass
- if the
ngClass
expressions get too big, it's a good idea to move the calculation of the styles to the component class - only for situations where we have a dynamically calculated embedded style should we use
ngStyle
, this should be rarely needed
I hope that this post helps in choosing how to style your components if you have some questions please let me know in the comments below and I will get back to you.
To get notified when more posts like this come out, I invite you to subscribe to our newsletter:
And if you would like to know about more Angular Core features, we recommend checking the Angular Core Deep Dive course, where component styling is covered in much more detail.
If you are just getting started learning Angular, have a look at the Angular for Beginners Course:
Other posts on Angular
Have also a look also at other popular posts that you might find interesting:
- Getting Started With Angular - Development Environment Best Practices With Yarn, the Angular CLI, Setup an IDE
- Why a Single Page Application, What are the Benefits ? What is a SPA ?
- Angular Smart Components vs Presentation Components: What's the Difference, When to Use Each and Why?
- Angular Router - How To Build a Navigation Menu with Bootstrap 4 and Nested Routes
- Angular Router - Extended Guided Tour, Avoid Common Pitfalls
- Angular Components - The Fundamentals
- How to build Angular apps using Observable Data Services - Pitfalls to avoid
- Introduction to Angular Forms - Template Driven vs Model Driven
- Angular ngFor - Learn all Features including trackBy, why is it not only for Arrays ?
- Angular Universal In Practice - How to build SEO Friendly Single Page Apps with Angular
- How does Angular Change Detection Really Work ?