Hello there!
With growing support for dark mode in native apps, developers are now looking to add it to their apps to support user preferences. Ionic makes it easy to change the themes of your app, including supporting dark color schemes.
In a normal scenario, when the user switches to Dark Mode in their operating system (Android - iOS - Web), your application will switch automatically to the dark theme. This happens using Media Queries and to be exact, one media query for the user's preferred color scheme.
In my situation I want to have a manual switch in my application that the user can flip to turn on/off the Dark Mode.
Let's dive right into it.
Steps:
- Create a new ionic/react project
- Modify the current theme variables to allow for manual Dark Mode switching
- Implement the controller to do the magic
Create a new ionic/react project
refering to the official documentation of ionic, I will simply do the following.
npm install -g @ionic/cli
ionic start AppWithDarkMode blank --type=react
Open up your newly created project in your preferred IDE, I like Visual Studio Code, it is super lightweight and supports ton of extensions witch makes your development much easier and much faster.
Now check if your application is running normally by going into the project directory and running ionic serve
cd AppWithDarkMode
ionic serve
Your browser will open up at http://localhost:8100/
by default and you're supposed to see something similar to this
Now moving to the next step.
Modify the current theme variables to allow for manual Dark Mode switching
Open up the project in your IDE, under src
=> theme
there's a file called variables.css
, open that up.
You can find two sections, one for the :root
tag, and another for the media query we talked about. Inside the media query, there are three sections body
, .ios body
, and .md body
. You can easily guess what these three sections are for. These are the dark theme colors for all different platforms running your application.
Now copy all those three sections (body
, .ios body
, and .md body
) outside of the media query and at the end of the file itself. Sure you can create a separate file and include that in your application, but that's up to you.
Now simply add .dark
to each of the newly created body
tags so that they can be like this (body.dark
, .ios body.dark
, and .md body.dark
).
Now we're ready for our final step.
Implement the controller to do the magic
I will begin by modifying the Home.tsx
file, which is the home page that displays in the app.
My current/auto-generated Home.tsx
file looks like this.
const Home: React.FC = () => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Blank</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Blank</IonTitle>
</IonToolbar>
</IonHeader>
<ExploreContainer />
</IonContent>
</IonPage>
);
};
I will remove the second IonHeader
tag in the IonContent
and leave the ExploreContainer
component, so it will look like this.
const Home: React.FC = () => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Blank</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<ExploreContainer />
</IonContent>
</IonPage>
);
};
Now we'll need a couple of imports. Please note that most of the following is to make the UI look good, the functionality itself is fairly simple.
Now the imports will look like this
import React from "react";
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonList, IonItem, IonIcon, IonLabel, IonToggle} from "@ionic/react";
import { moon } from "ionicons/icons";
import ExploreContainer from "../components/ExploreContainer";
import "./Home.css";
We can use our newly imported components like this:
const Home: React.FC = () => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Blank</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<IonList className="ion-margin-top">
<IonItem>
<IonIcon slot="start" icon={moon} />
<IonLabel>Dark Mode</IonLabel>
<IonToggle
slot="end"
name="darkMode"
onIonChange={toggleDarkModeHandler}
/>
</IonItem>
</IonList>
<ExploreContainer />
</IonContent>
</IonPage>
);
};
You can tell directly that it's complaining about onIonChange={toggleDarkModeHandler}
, that's because we haven't implemented that method yet.
Go ahead and create that method inside the Home
component like this:
const toggleDarkModeHandler = () => {
document.body.classList.toggle("dark");
};
Like I said, the functionality itself is fairly simple.
Now return to your browser, and you'll see that the switch is there and is working!
Extra
We can do a little bit of an extra styling to the icon so that it looks like this
- In the
Home.css
file add the following css classes.
.component-icon {
border-radius: 50%;
padding: 7px;
height: 18px;
width: 18px;
margin-top: 5px;
margin-bottom: 5px;
}
.component-icon-dark {
background: var(--ion-color-step-850, #27323e);
color: var(--ion-item-background, #fff);
}
And simply use the new CSS classes on the IonIcon
component.
<IonIcon
slot="start"
icon={moon}
className="component-icon component-icon-dark"
/>
That's it!
Complete Home.tsx
file
import React from "react";
import {IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonList, IonItem, IonIcon, IonLabel, IonToggle} from "@ionic/react";
import { moon } from "ionicons/icons";
import ExploreContainer from "../components/ExploreContainer";
import "./Home.css";
const Home: React.FC = () => {
const toggleDarkModeHandler = () => {
document.body.classList.toggle("dark");
};
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Blank</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<IonList className="ion-margin-top">
<IonItem>
<IonIcon
slot="start" icon={moon} className="component-icon component-icon-dark" />
<IonLabel>Dark Mode</IonLabel>
<IonToggle slot="end" name="darkMode" onIonChange={toggleDarkModeHandler} />
</IonItem>
</IonList>
<ExploreContainer />
</IonContent>
</IonPage>
);
};
export default Home;
Top comments (2)
This works fine on Home.tsx. But my other tabs are not getting dark. What can I do to get all my app, all my tabs dark?
Can we use 2 IonButton instead to change 2 different color? Thank you