loading...
Cover image for How to Create a Dark/Light Mode Switch with Styled JSX

How to Create a Dark/Light Mode Switch with Styled JSX

cesarwbr profile image Cesar William Alvarenga ・3 min read

When you have a Next.js application you probably use Styled JSX to write the style of your components. It is because Next.js includes Styled JSX by default in your project. If this is your case or you’re just using Styled JSX by yourself and you want to implement a Dark/Light mode switch on your website this article is for you.

We will implement a simple theme toggle (Dark <-> Light ) using some techniques with this CSS-in-JS library and JavaScript in four steps.

First Step: Defining Your Themes

The first step is to choose the right colors for your dark and light themes. Defining the colors that will fit between these two themes can become a challenge. It is because you have to take care of design principles like card depth, background color, font color, usability, and accessibility (a11y). Here is a good video that shows some best practices that you (or your designer) can follow in order to create a successful color decision.

Second Step: Creating the CSS Variables

With the design of our application, we can start creating the CSS variables that we will use along with our project. To do that we will use global styles to create our variables. Styled JSX allows us to add global styles using <style jsx global, inside this we will define our theme variables and their values. We will take the light theme as our default theme (it could be the dark theme) and we set that in the root element of our document tree represented by the selector :root.

<style jsx global>{`
  :root {
    --bg-color: white;
    --primary-color: black;
    --secondary-color: rgb(113, 128, 150);
    {/* other variables */}
  }
`}</style>

Third Step: Creating the Secondary Theme

Now it’s time to add the secondary theme values (in our case the dark theme) that will override the default theme defined previously. We will define our secondary theme in the theme data attribute of the root element of our document.

<style jsx global>{`
  :root {
    --bg-color: white;
    --primary-color: black;
    --secondary-color: rgb(113, 128, 150);
    {/* other variables */}
  }

  [data-theme="dark"] {
    --bg-color: #121212;
    --primary-color: #f4f4f6;
    --secondary-color: #8999b0;
    {/* other variables */}
  }
`}</style>

Last Step: Switching Between Light and Dark Themes

In this step, with JavaScript we will use the definitions that we did in our Styled JSX to switch between light theme and dark theme. For that, basically, we will read and write the data attribute theme that we are using in our root element. Changing this attribute will automatically change the value of the style variable for us.

function switchTheme() {
  const currentTheme = document.documentElement.dataset.theme;

  if (currentTheme === 'dark') {
    document.documentElement.dataset.theme = 'light';
  } else {
    document.documentElement.dataset.theme = 'dark';
  }
}

Example

Let’s create a simple React component with these steps altogether.
You can notice that we are using the CSS variables to determine the colors of our themes in our document elements. As we defined the variables in the JSX global, we can use them in the children’s components as well.

export default function Home() {
  function switchTheme() {
    const currentTheme = document.documentElement.dataset.theme;

    if (currentTheme === "dark") {
      document.documentElement.dataset.theme = "light";
    } else {
      document.documentElement.dataset.theme = "dark";
    }
  }

  return (
    <div>
      <button onClick={switchTheme}>Switch Theme</button>
      <h1>Example</h1>
      <h3>This is a simple dark mode example</h3>

      <style jsx global>{`
        :root {
          --bg-color: white;
          --primary-color: black;
          --secondary-color: rgb(113, 128, 150);
        }

        [data-theme="dark"] {
          --bg-color: #121212;
          --primary-color: #f4f4f6;
          --secondary-color: #8999b0;
        }

        body {
          background: var(--bg-color);
          transition: background 0.5s;
        }

        h1 {
          color: var(--primary-color);
        }

        h3 {
          color: var(--secondary-color);
        }
      `}</style>
    </div>
  );
}

Click here to see a working example.

Discussion

pic
Editor guide