Dark Mode Tailwind & React (No flashing!)
Tags: tutorial, react, tailwindcss, darkmode
Published: 2023-08-05 11:08:23

## Initial Set up

First Lets set up our initial Project.
```bash
git clone https://github.com/hyeo151/Darkmode-Tutorial-React-Tailwind.git

cd Darkmode-Tutorial-React-Tailwind

npm install

npm run dev
```
When you start your server,you will either see light mode or dark mode depending on your OS color preference.

Light Mode
![Light Mode Preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5uuunbqm7lxut24mwukp.png)
Dark Mode
![Dark Mode Preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/550obbo34lndeo56tkfp.png)

> By default tailwind uses `prefers-color-scheme` CSS media feature to enable Dark mode.

## Class Strategy Set up
If we wish to add Dark mode which can be toggled by a user we can use `class strategy`

Go to tailwind.config.js and add `darkMode: 'class'`

```js
/** @type {import('tailwindcss').Config} */
export default {
  content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  darkMode: 'class',
  theme: {
    extend: {},
  },
  plugins: [],
};

```

Now we can add darkmode by simply adding `class="dark"` in our html element in `index.html` like this, 

enables dark mode
`<html lang="en" class="dark">`

disable dark mode
`<html lang="en" class="">`

## Dark Mode Logic
Now that we have set up class Strategy in our project let's add our logic for dark mode.

First we will add following script in our `index.html` in `head element`. Add this script before any other scripts or links.

```html    
<script>
      const initialTheme =
        localStorage.theme === "dark" ||
        (!("theme" in localStorage) &&
          window.matchMedia("(prefers-color-scheme: dark)").matches);
      if (initialTheme) {
        window.document.documentElement.classList.add("dark");
      }
</script>
```

> Script like this is called Render-blocking resources which prevents a web page from loading quickly. However we use this method as opposed to using useEffect hook to avoid flashing
 
This Script instruct following, 

> [if local storage theme variable is dark]
> OR
> [if theme variable doesn't exist in local storage AND OS preference is dark]
> THEN set our page as dark mode. 

This script will load correct mode on initial page load.

Now Let's add darkTheme state for our project.
Go to `App.jsx` and declare darkTheme state.
We can use initialTheme that we declared previously and use it as our initial state.

```react  
const [darkTheme, setDarkTheme] = useState(initialTheme);
```

and we show icon according to our darkTheme state

```react          
{darkTheme ? (
  <i className="fa-solid fa-sun"></i>
) : (
  <i className="fa-regular fa-moon"></i>
)}
```
then we add clicked button which to toggle this state.

```react        
onClick={() => {
  handleThemeSwitch(setDarkTheme);
}}
```

Define function handleThemeSwitch

```react
const handleThemeSwitch = (setDarkTheme) => {
  if (document.documentElement.classList.contains("dark")) {
    document.documentElement.classList.remove("dark");
    localStorage.theme = "light";
    setDarkTheme(false);
    return;
  }
  localStorage.theme = "dark";
  document.documentElement.classList.add("dark");
  setDarkTheme(true);
};
```
Final Code will look like this,

```react
import { useState } from "react";
import "./App.css";

const handleThemeSwitch = (setDarkTheme) => {
  if (document.documentElement.classList.contains("dark")) {
    document.documentElement.classList.remove("dark");
    localStorage.theme = "light";
    setDarkTheme(false);
    return;
  }
  localStorage.theme = "dark";
  document.documentElement.classList.add("dark");
  setDarkTheme(true);
};

function App() {
  const [darkTheme, setDarkTheme] = useState(initialTheme);
  return (
    <div className="max-w-md rounded-md bg-slate-200 p-5 dark:bg-slate-300/80">
      <h1 className="mb-2 text-xl font-bold">Tailwind Dark/Light Mode</h1>
      <p className="mb-4">
        In this tutorial we will be learning how to enable dark mode for your
        tailwind react website/app
      </p>
      <button
        className="rounded-md bg-slate-500 px-5 py-1 font-bold"
        onClick={() => {
          handleThemeSwitch(setDarkTheme);
        }}
      >
        <div className="moon">
          {darkTheme ? (
            <i className="fa-solid fa-sun"></i>
          ) : (
            <i className="fa-regular fa-moon"></i>
          )}
        </div>
      </button>
    </div>
  );
}

export default App;
```

Now whenever user click on the switch button we can switch the dark mode.

If you get stuck you can check out the solution branch

```bash
git checkout solution 
```

Thank you for reading! 

If you liked this post please like, comment and share.
Ask questions in comment section : )