Add themes to Angular using CSS variables

Ertunga Bezirgan
codeshakeio
Published in
4 min readAug 2, 2022
Photo by Jeremy Bezanger on Unsplash

Providing different themes for users to choose from has become pretty much a standard these days and it’s quite easy to implement using Angular. In this article, we are going to learn how to add themes to Angular apps using a simple service and the power of CSS variables (aka CSS custom properties).

Here is what we are aiming for

  • Multiple themes to choose from (light, dark, and possibly more)
  • Store the selected theme in local storage
  • Apply stored theme upon revisit

And here is what the final result looks like,

Overview

We are going to create a service to hold the “active theme” as a state and also it will be responsible for changing the theme. This is going to be achieved by swapping CSS classes associated with the theme. CSS classes in return will be responsible for the theme change via CSS variables.

Define Themes

Let’s jump right into it by defining the themes we want to have in the application. To do so, we are going to create a file called theme.ts and expose an object from it. Keys of the object will be the theme names and their values will be the CSS classes associated with the theme. Here is an example in which we defined light, dimmed, and dark themes:

Theme Classes

In the next step, we are going to create CSS classes. Navigate to your global stylesheet (styles.{scss,css,less}) and add the following code to it.

You can add more variables if you need to. Notice that I already used two of the CSS variables in the body element. Right now, it doesn’t do anything because we haven’t set the theme just yet.

Theme Service

Now that we defined our themes and created CSS classes, we are going to create a service to hold the active state and change it. Create a service called theme and add the following code to it.

There are a couple of things to mention here.

  • BehaviorSubject is used to keep the active theme as a state.
  • activeTheme getter method is created to get the active theme. An observable alternative, activeTheme$, is also added in case we want to subscribe to it.
  • To set the theme, set(...) method is created which takes “theme name” as an argument. Using the themes we defined earlier in theme.ts, it will remove and add CSS classes to the documentElement.
  • Also, I’ll throw in a getter method called themeNames to list all the possible themes.

Usage

To use the service, inject it into the app component and call the set(...) method.

And that’s it, theme selection is working. This will set the ‘light’ theme by default. You can add more styles for the component and start using themes in the application.

This is nice and all but regardless of what the user selects, the selection will be lost on a page reload since it’s not saved anywhere. Let’s fix this problem by adding local storage to the implementation.

With Local Storage

We’ll change some code in the app component.

  1. Check local storage first to see if a value is set.
  2. If there is a value, and the saved value is listed in the theme.ts we created earlier, set the theme. If not, set the ‘light’ theme as the default theme.
  3. Start listening to the theme changes using activeTheme$ observable and set the new theme to the local storage.

Here is the new implementation of app component,

And with these small changes, the selected theme will be set when you reload the page or revisit it later on.

Bonus: Use it with Tailwind CSS

The same service can be used to toggle light and dark modes in Tailwind CSS. You can refactor it in two ways:

  1. Either change theme.ts and remove “-theme” suffix from themes. And don’t forget to remove them from the classes in styles.{scss,css,less} as well. And finally, add the following line to your tailwind.config.js file.
module.exports = {
// ...
darkMode: 'class'
}

2. Second way is to keep everything as is and just add the following to tailwind.config.js

module.exports = {
// ...
darkMode: ['class', '.dark-theme']
}

Done! 🎉

And that’s really it!

--

--