Change body background with data-theme attribute on click with React

Viewed 86

I'm trying to change the theme in an app using the data attribute and then changing the CSS variables according to the different data-theme values.

In the App component, I check if the user has a default theme set, and use that to set new theme on click

import "./styles.css";
import useLocalStorage from "use-local-storage";

export default function App() {
  // Check user set theme mode...
  const defaultDark = window.matchMedia("(prefers-color-scheme: dark)").matches;

  // Create theme mode state...
  const [theme, setTheme] = useLocalStorage(
    "theme",
    defaultDark ? "dark" : "light"
  );

  // Handle on click from the theme switcher...
  const clickHandler = () => {
    const newTheme = theme === "light" ? "dark" : "light";

    setTheme(newTheme);
  };
  return (
    <div className="App" data-theme={theme}>
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={() => clickHandler()}>Dark Mode</button>
    </div>
  );
}

In the styles.css I set the different variables to define the theme

/* Set the dark mode variables... */
[data-theme="dark"] {
  --background: black;
  --title-text: white;
  --desc-text: grey;
}

/* Set the light mode variables... */
[data-theme="light"] {
  --background: white;
  --title-text: black;
  --desc-text: grey;
}

/* Page Styles... */
body {
  padding: 0;
  margin: 0;
  background: var(--background);
}

/*The rest of the CSS...*/

The rest of the elements work fine as they are wrapped in an element that has the data-theme attribute. However, the body is not wrapped with the data-theme attribute, so there is no change in the body background. In this example, I used .App but I would like to change the body instead. Is there a way to wrap the body in the data-theme attribute in React?

Here is the link to the full code in CodeSandbox Full code on CodeSandbox

1 Answers

How about wrap App with div.body them pass data-theme into .body instead and make div.body cover body

<div className='body' data-theme={theme}>
    <div className='App'></div>
</div>
Related