Dynamic Ionic Theming

With the shift to CSS variables for much of the styling of the Ionic components, a popular question on the Ionic forums is “How do I dynamically change the look my application at runtime?” For example, wanting a light or dark theme, or have the controls match the logo colors of your favorite sports team. In this post, I am going to show you the basics for doing this. To begin, generate a new Ionic application:

$ ionic start themedemo blank --type=angular

Once it is finished generating, open the home.html. Let’s replace the template code with the following:


<ion-header>
 <ion-toolbar>
   <ion-buttons slot="secondary">
     <ion-button fill="outline">
       <ion-icon slot="start" name="star"></ion-icon>
       Star
     </ion-button>
   </ion-buttons>
   <ion-title>Theme Demo</ion-title>
   <ion-buttons slot="primary">
     <ion-button color="danger" fill="outline">
       Edit
       <ion-icon slot="end" name="create"></ion-icon>
     </ion-button>
   </ion-buttons>
 </ion-toolbar>
</ion-header>
<ion-content>
 <ion-button (click)="colorIt()">Color Theme</ion-button>
 <ion-button (click)="setTheme('dark')">Dark Theme</ion-button>
 <ion-button (click)="setTheme('light')">Light Theme</ion-button>
</ion-content>

view raw

home.page.html

hosted with ❤ by GitHub

This new template has some elements in the ion-header and three buttons that will we can use to alter the applied CSS variables.

Let’s set up the CSS variables that we will be interacting with, open the variables.scss file that is located in the theme directory. If you have not worked with this file before, this is where all the default Ionic theme colors are defined; primary, secondary, etc. In the :root declaration, we are going to add two new variables that we will be changing via our code. Add a –mycolor variable and set its value to rebeccapurple, and another variable –mytextcolor and define its value as #fff. Your variables.scss file should look like this at the start:


:root {
 –mycolor: rebeccapurple;
 –mytextcolor: #fff;
 /** primary **/
 –ion-color-primary: #3880ff;
 –ion-color-primary-rgb: 56, 128, 255;
 –ion-color-primary-contrast: #ffffff;
 –ion-color-primary-contrast-rgb: 255, 255, 255;
 –ion-color-primary-shade: #3171e0;
 –ion-color-primary-tint: #4c8dff;
 …more…
}

view raw

home.page.scss

hosted with ❤ by GitHub

With our two variables now defined, we can now apply them. Open the global.scss file. This file is the proper place for setting any global CSS to our application. In this simple example, we are just going to change the background color and the text color of our Ionic toolbar. By checking the Ionic documentation on that component, there are two defined CSS variables for those properties; –background and –color respectively. If we just want to override the values, we could set them directly like this:


ion-toolbar {
   –background: rebeccapurple;
   –color: #ffffff;
}

view raw

global.scss

hosted with ❤ by GitHub

Unfortunately, we can not directly assign a CSS variable to another in this fashion. Instead, we need to declare it as a var before we can set the value of the property. To do this, we change our CSS to use the var function (https://developer.mozilla.org/en-US/docs/Web/CSS/var):


ion-toolbar {
   –background: var(–mycolor);
   –color: var(–mytextcolor);
}

view raw

global.scss

hosted with ❤ by GitHub

If you saved all the files and ran $ ionic serve, you should see your header’s toolbar in a nice purple and the text in white. Since there are no methods for those buttons to call they won’t function (and odds are your editor might be warning you about that fact).

Switching to the home.page.ts file, let’s add those methods. After the class definition, add an object that will define our theme colors. For more robust theming I would suggest creating a service or module that contains your theme management, but this example we will not add that level of complexity. Here is our new variable:

theme = {
  mycolor: 'rebeccapurple',
  mytextcolor: '#fff'
};

Currently, the Blank template’s component does not include a constructor, so let’s add a basic one:

constructor() { }

For the colorIt method, I want to show you how to set the property directly. This option works well if you are setting a small number of variables. To do this we will call document.documentElement.style.setProperty() method. This method has three parameters: the property name, the value (optional), and the priority (optional). Since we are interacting with CSS variables, we can not set the property name as –mycolor. Instead, we need to wrap the CSS variable with a ` or backtick. The new value that we want to set can be wrapped with the standard single quote. Here is what the code should look like:

colorIt() {
  document.documentElement.style.setProperty(`--mycolor`, '#ccc');
  document.documentElement.style.setProperty(`--mytextcolor`, '#000');
}

 Those two lines will change the CSS variables to their new values, and trigger a repaint of the screen.

But what if swapping themes requires changing more than just a few variables? Let me show you the foundation for solving that challenge. Two of the buttons in our template called the setTheme method, each passing in a string that was a theme name (light or dark). This method will update the theme object we defined in our class with new values. But the workhorse of the method is actually the forEach loop that we will call. This will walk through each of the properties names and set their values. Here is the full code:

setTheme(userTheme: string) {
  if (userTheme === 'dark') {
    this.theme.mycolor = 'rebeccapurple';
    this.theme.mytextcolor = '#fff';
  } else {
    this.theme.mycolor = '#ccc';
    this.theme.mytextcolor = '#000';
  }

  Object.keys(this.theme).forEach(k =>
    document.documentElement.style.setProperty(`--${k}`, this.theme[k])
  );
}

If you have not seen the ${} before, this is ES6’s template notation. If you run the application now you should be able to toggle the header bar color and text color. 

theme_sample

So, there are the basics for having dynamic themes in Ionic 4. Like I mentioned, you are probably going to want to expand upon this to have a proper service or module to manage your theming across your application. Feel free to ping me with questions or other design challenges in Ionic.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.