Part 26: Switching Themes Dynamically: Implementing a User-Selectable Dark Mode

[Pages] Client-side Functionality

[Pages] Client-side Functionality

In our previous discussion, we set up CSS variables for light and dark themes. Now, we’re taking this a step further by allowing users to dynamically switch between these themes using a "ThemeSwitch" button. This post will guide you through the process of implementing this feature using React and styled-jsx.

Default to Light Theme

Initially, we want our website to use the light theme by default. This means our default CSS variables should reflect the light theme settings. We will move the dark theme styles to a separate component to apply them conditionally.

Using styled-jsx for Global Styles

In a React application, styled-jsx is a popular way to apply scoped styles to components. However, for our theme switcher, we need these styles to be global. Styled-jsx allows us to apply styles globally using the global property.

Step 1: Create a Dark Theme Component

To manage our dark theme styles efficiently, we'll create a new component named DarkTheme. This component will render the necessary styles for the dark theme.

// components/DarkTheme.js

function DarkTheme() {
  return (
    <style jsx global>{`
      :root {
        --background-color: rgb(14, 14, 14);
        --link-color: rgb(234, 207, 3);
        --text-color: rgb(230, 230, 230);
      }
    `}</style>
  );
}

export default DarkTheme;

This component uses styled-jsx to define global CSS variables for the dark theme. These variables will override the default light theme settings when applied.

Step 2: Modify the ThemeSwitch Component

In the ThemeSwitch component, we will manage the theme switching logic using React's state and conditional rendering.

// components/ThemeSwitch.js

import { useState } from 'react';
import DarkTheme from './DarkTheme';

function ThemeSwitch() {
  const [darkMode, setDarkMode] = useState(false);

  return (
    <>
      <button onClick={() => setDarkMode(!darkMode)}>
        {darkMode ? 'Switch to Light Mode' : 'Switch to Dark Mode'}
      </button>
      <style jsx>{`
        button {
          background: none;
          border: none;
          color: inherit;
          cursor: pointer;
        }
      `}</style>
      {darkMode && <DarkTheme />}
    </>
  );
}

export default ThemeSwitch;

Conditional Rendering

  • State Management: We use a state variable darkMode initialized to false. This indicates that the light theme is active by default.

  • Button Click Logic: When the button is clicked, the darkMode state toggles between true and false.

  • Apply Dark Theme Conditionally: We use conditional rendering to apply the DarkTheme component only when darkMode is true.

Step 3: Update Global Styles

Ensure your globals.css file reflects only the light theme, as the dark theme styles are now managed by the DarkTheme component:

/* styles/globals.css */

:root {
  --background-color: white;
  --link-color: darkred;
  --text-color: black;
}

body {
  font-family: Arial, Helvetica, sans-serif;
  background-color: var(--background-color);
  color: var(--text-color);
}

a {
  color: var(--link-color);
  text-decoration: none;
}

Testing the Implementation

With this setup, the "ThemeSwitch" button dynamically changes the theme when clicked. Inspecting the page elements will show how the CSS variables change according to the active theme, providing a practical debugging method.

Conclusion

By organizing our styles into separate components and using styled-jsx for global theming, we've created a flexible and maintainable theme-switching mechanism. This setup is applicable in any React application, providing a responsive and user-friendly experience. In future updates, we can explore additional features and optimizations for a more robust theming system.

Last updated