When I created my last app, "daily baby care" (an app for my wife and I, to track our 3 months infant meals & naps), I wanted to add a button in the app to force the light/dark theme.
Something like this:
So how would it work? Well, by default, an Ionic app will use the media queries to know when to use the dark mode:
But I could not find any. It seems impossible to force the prefers-color-scheme in the app without having to change the scss files.
So I started searching for an easy solution, but then it hit me: just take control of how it works.
What do I really want? I want :
auto mode by default
to be able to force it in dark mode
to be able to force it in light mode
The default code of an Ionic app makes it impossible to "force" it in dark. So I have to change the logic here.
My idea was to add 3 new possible classes on the root body of the app.
If the body has the class auto, it will use the light theme or the dark theme (if prefers-color-scheme: dark).
If the body has the dark class, it will use the dark theme
If the body has the light class, it will use the light theme
How to do that? Simple, just a few steps.
First, I'll split my scss files into 4 files :
The variables.scss will contain the default light theme:
Then, in my variables-dark.scss, I'll create some mixins to contain the default dark theme variables:
Now, I want to @include those mixins in 2 situations :
when there is the dark class on the body of the app
when there is the auto class on the body of the app AND the prefers-color-scheme: dark
To do that, I'll use those mixins in my theme-dark.scss file:
As you can see, if the body has the dark class, I'll @include my dark mixins.
Or, if the prefers-color-scheme: dark AND the body has the class auto, I'll include my dark mixins.
Seems like a smart solution right? Now I just have to change the class on my body.
BTW, don't forget to add your new scss files to your project file:
So, to add the class to my body, I'll create a ColorSchemeService that will add/remove the wanted classes onto the body, by using @Inject(DOCUMENT) :
Of course it could be better to use an ENUM for the color schemes, and avoid to store it in the localStorage, but, hey, what you gonna do :)
Finally, I just have to use that service when the app loads:
And when I click on one of my buttons:
And... it works!
Just a tiny little last thing, by default, the light theme doesn't declare it's color and background-color. That's why I added the theme.scss file, to define them and avoid some weird backgrounds in forced modes: