<!--
Simple React Dark Mode.
Uses state to set a class on the body if dark mode is enabled.
-->

<div id="app"></div>
*,
*:before,
*:after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  color: #1a202c;
  transition: color 0.2s ease-in;
}

#app {
  height: 100vh;
  width: 100%;
}

main {
  background-color: #f7fafc;
  height: 100%;
  width: 100%;
  padding: 20px;
  transition: background-color 0.2s ease-in;
}

header {
  position: absolute;
  right: 2rem;
}

#container {
	 display: flex;
	 height: 100%;
	 width: 100%;
	 align-items: center;
	 justify-content: center;
	 flex-direction: column;
}
 #container h1 {
	 padding: 0;
	 margin: 0 0 10px 0;
}
 #container p {
	 opacity: 0.8;
}

#toggle {
	 width: 50px;
	 display: flex;
	 padding: 5px;
	 background-color: #1a202c;
	 border-radius: 1000px;
	 cursor: pointer;
	 box-shadow: 0px 5px 20px -10px #000;
	 transition: background-color 0.2s ease-in;
}

#toggle .toggle-inner {
	 width: 20px;
	 height: 15px;
	 background-color: white;
	 border-radius: 1000px;
	 transition: margin-left 0.2s ease-in, background-color 0.2s ease-in;
}

#toggle .toggle-active {
	 margin-left: 20px;
}

.dark-mode {
	 color: white;
}

.dark-mode main {
	 background-color: #1a202c;
}

.dark-mode #toggle {
	 background-color: white;
}

.dark-mode #toggle .toggle-inner {
	 background-color: #1a202c;
}
function Header() {
  const [ darkMode, setDarkMode ] = React.useState(false)
   
  React.useEffect(() => {
    const body = document.body
    const toggle = document.querySelector('.toggle-inner')
    
    // If dark mode is enabled - adds classes to update dark-mode styling.
    // Else, removes and styling is as normal.
    if( darkMode === true ) {
      body.classList.add('dark-mode')
      toggle.classList.add('toggle-active')
    } else {
      body.classList.remove('dark-mode')
      toggle.classList.remove('toggle-active')
    }
  }, [darkMode])
  
  return (
    <header>
      <div
        id="toggle"
        onClick={() => darkMode === false ? setDarkMode(true) : setDarkMode(false)}
      >
        <div className="toggle-inner"/>
      </div>
    </header>
  )
}

function App() {
  return (
    <main>
      <Header />
      <div id="container">
        <h1>React Dark Mode</h1>
        <p>Uses state to set a class on the body if dark mode is enabled.</p>
        <p>Implementation is done due to a side effect</p>
      </div>
    </main>
  )
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js