Dynamic Theming Your Ionic App Last update: 2017-06-06

Dynamic Theming Your Ionic App

Theming your Ionic app is an awesome way to quickly change the styling for all parts of your app. But what happens if you want to change your styling while running, like toggling a day or night mode?

We can’t change the selected theme of our Ionic app at runtime, so we need to become a bit more creative. In this tutorial we will see how to quickly change the styling of our app just like in the image below!

ionic-dynamic-style-toggle

Preparing our App

We start as always with blank Ionic app and generate a provider which will be used later to tell us which theme is currently used. Go ahead and run:

ionic start devdacticDynamicStyle blank
cd devdacticDynamicStyle
ionic g provider settings

Now inside our app we need to create 2 files inside the src/theme folder, as these will reflect how our different themes will look like. Call the first file theme.light.scss and insert:

.light-theme {
  ion-content {
    background-color: #fff;
  }

  .toolbar-background {
    background-color: #fff;
  }
}

The second one is called theme.dark.scss and you can insert this:

.dark-theme {
  ion-content {
    background-color: #090f2f;
    color: #fff;
  }

  .toolbar-title {
    color: #fff;
  }

  .header .toolbar-background {
    border-color: #ff0fff;
    background-color: #090f2f;
  }
}

Now we got 2 styling files which define some CSS classes for either a light or a dark theme. We also need to make them available, so put these import statements somewhere in your src/theme/variables.scss:

@import "theme.light";
@import "theme.dark";

We have now created and imported our theming files, but as the class is never added those stylings will never be applied. So that’s where our route is taking us soon.

Creating the Settings provider

But before we get there we need to implement our helper provider. The provider holds the current selected theme, we can change the theme and we can grab the theme.

In general nothing special, but we want to make sure that our app always get’s the latest selected theme, and therefore we use a type called BehaviourSubject which inherits from Subject and then from Observable, so it’s more or less a special type of Observable.

Using this type has 2 benefits for our app:

  • We can set a start value which will be emitted to all subscribers at first subscription
  • We can call next() and all subscribers will immediately get the new value

So inside our Constructor we set the initial value, when we want to set it to a new value we call the next() method and finally we return it to our views as an Observable because there we don’t need any more specials and can simply use it like a standard Observable.

open your src/providers/settings/settings.ts and insert:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/Rx';

@Injectable()
export class SettingsProvider {

    private theme: BehaviorSubject<String>;

    constructor() {
        this.theme = new BehaviorSubject('dark-theme');
    }

    setActiveTheme(val) {
        this.theme.next(val);
    }

    getActiveTheme() {
        return this.theme.asObservable();
    }
}

Now we can change the theme from everywhere inside our app and the subscribers will be notified about the new value so we can change it accordingly.

Toggling our App Theme

To toggle our app theme, we add a simple button and toggle function to our page. We also subscribe to the current value and always update our variable inside the class once a new value comes to us in the subscribe() block.

Open your src/pages/home/home.ts and insert:

import { SettingsProvider } from './../../providers/settings/settings';
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  selectedTheme: String;

  constructor(public navCtrl: NavController, private settings: SettingsProvider) {
    this.settings.getActiveTheme().subscribe(val => this.selectedTheme = val);
  }

    toggleAppTheme() {
    if (this.selectedTheme === 'dark-theme') {
      this.settings.setActiveTheme('light-theme');
    } else {
      this.settings.setActiveTheme('dark-theme');
    }
  }

}

Now we need to craft a little view around this and add the button to toggle our styling. Nothing really fancy here, so open your src/pages/home/home.html and change it to:

<ion-header>
  <ion-navbar>
    <ion-title>
      Night & Day
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <p text-center>I shine at night and glow at day.</p>
  <button ion-button full icon-left (click)="toggleAppTheme()">
    <ion-icon  name="bulb"></ion-icon>Toggle Theme
  </button>
</ion-content>

We are now able to toggle our style, but nothing happens! Did you think it would work now?

Well the most important part is still missing, because we are currently just updating a random variable of a provider but never really use it.

Adding the final Piece of Magic to Theming

This brings us to the last missing piece of our dynamic theming. The trick we use is to apply the selected theme as a class to the root component of our app!

Therefore, we need to also subscribe to the value like we did before inside our src/app/app.component.ts like this:

import { SettingsProvider } from './../providers/settings/settings';
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import { HomePage } from '../pages/home/home';
@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage:any = HomePage;
  selectedTheme: String;

  constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen, private settings: SettingsProvider) {
    this.settings.getActiveTheme().subscribe(val => this.selectedTheme = val);

    platform.ready().then(() => {
      statusBar.styleDefault();
      splashScreen.hide();
    });
  }
}

There is always a HTML file connected to this root component, and this is the place where we add the class using the Angular way of dynamically adding a class.

Open your src/app/app.html and add it like this:

<ion-nav [root]="rootPage" [class]="selectedTheme"></ion-nav>

Now whenever we change our variable inside the provider (through our toggle) the new theme will be set as a

Run your app and play around with your night and day theme now!

Conclusion

We could now add even more themes and toggle them dynamically to change the UI of our Ionic app at runtime. Of course you need to be aware what CSS you define at the root level because it will be applied to all pages, so try to be specific with your CSS selectors there to only target what you really want to change.

You can find a video version of this article on dynamic Ionic theming below.