Theme Switcher

Build a toggle that switches the color scheme of the page between light and dark modes.

Solution

Headline

Section

This solution toggles CSS root values for font and background colours.

If light we use:

--fontColor: black; --bgColor: white;

If dark we use:

--fontColor: white; --bgColor: black;

Better solutions would also take account of the users preferences. You can see from this article how you need to access the system settings with media queries.

Explanation

isDark useState

The user preference for light or dark mode is stored in the state variable, isDark.

toggleDarkMode function

The toggleDarkMode function very simply returns the opposite of the current state. This is attached to the Toggle Theme button.

Adding the style to elements

A conditional style has been added to the container element with a ternary operator with either lightMode and darkMode being assigned.

The trick to changing the styles in CSS

The use of CSS Variables controls the output colours.

Both lightMode and darkMode have their own values for the variables --fontColor and --bgColor.

Look to the other CSS classes to see how those variables have been used to assign key colours. This means they can alter based off of which of the two classes lightMode or darkMode is used.

Code

import { useState } from "react";
import styles from "./Solution.module.css";

const Solution = () => {
  const [isDark, setIsDark] = useState(false);

  const toggleDarkMode = () => setIsDark((prevMode) => !prevMode);

  return (
    <div
      className={`${styles.container} ${
        isDark ? styles.darkMode : styles.lightMode
      }`}
    >
      <button
        onClick={toggleDarkMode}
        aria-label="Dark mode toggle"
        className={styles.buttonTheme}
        type="button"
      >
        Toggle Theme
      </button>
      <h1>Headline</h1>
      <section className={styles.section}>
        <h2>Section</h2>
        <p>
          This solution toggles CSS root values for font and background colours.
        </p>
        <p>If light we use:</p>
        <p>--fontColor: black; --bgColor: white;</p>
        <p>If dark we use:</p>
        <p>--fontColor: white; --bgColor: black;</p>
        <p>
          Better solutions would also take account of the users preferences. You
          can see from this{" "}
          <a href="https://blog.logrocket.com/dark-mode-react-in-depth-guide/#using-system-settings">
            article
          </a>{" "}
          how you need to access the system settings with media queries.
        </p>
      </section>
    </div>
  );
};

export default Solution;

Styling

.lightMode {
  --fontColor: black;
  --bgColor: white;
}

.darkMode {
  --fontColor: white;
  --bgColor: black;
}

.buttonTheme {
  color: var(--fontColor);
  padding: 10px;
  margin: 10px 0 20px;
  background-color: var(--bgColor);
  cursor: pointer;
  border: 2px solid;
  border-color: var(--fontColor);
  scale: 1;
  transition: scale 0.3s;
}

.buttonTheme:hover {
  scale: 1.1;
}

.buttonTheme:active {
  scale: 0.9;
}

.container {
  padding: 10px;
  transition: 0.3s;
  color: var(--fontColor);
  background-color: var(--bgColor);
}

.section {
  max-width: 400px;
  margin: 20px 0;
  padding: 20px;
  border: 1px solid;
  border-color: var(--fontColor);
}

.section p {
  margin: 0.5rem 0;
}

.section a,
.section a:visited,
.section a:active {
  color: inherit;
  text-decoration: underline;
}

Links