Ionic React Manual Dark Mode Switch
Tags: ionic, react, typescript, darkmode
Published: 2020-04-30 11:21:20

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](https://ionicframework.com/docs/theming/dark-mode).

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](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-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](https://dev-to-uploads.s3.amazonaws.com/i/olf5bf6wrw0qc7jxqigo.png)

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](https://ionicframework.com/docs/react/quickstart) 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](https://code.visualstudio.com/), 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
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/xx9xiqcvqgh08j0ewnav.png)

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](https://dev-to-uploads.s3.amazonaws.com/i/ea9etx2ly6mnbxmtssj1.PNG)

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!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/xppwm7i8rp9pyejna41j.png)

### Extra
We can do a little bit of an extra styling to the icon so that it looks like this
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/olf5bf6wrw0qc7jxqigo.png)

*  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;

```