DEV Community

Cover image for Ionic React Manual Dark Mode Switch
Ibrahim Awad
Ibrahim Awad

Posted on • Updated on

Ionic React Manual Dark Mode Switch

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.
Alt Text

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Your browser will open up at http://localhost:8100/ by default and you're supposed to see something similar to this
Alt Text

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).

Alt Text

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

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");
  };
Enter fullscreen mode Exit fullscreen mode

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!

Alt Text

Extra

We can do a little bit of an extra styling to the icon so that it looks like this
Alt Text

  • 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);
}
Enter fullscreen mode Exit fullscreen mode

And simply use the new CSS classes on the IonIcon component.

<IonIcon
    slot="start"
    icon={moon}
    className="component-icon component-icon-dark"
/>
Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

Discussion (1)

Collapse
lilycjh profile image
lilycjh

Can we use 2 IonButton instead to change 2 different color? Thank you