Recently, I was challenged to code a Dark Mode feature for a website using React. I decided to implement the same feature on my own blog.
It’ll seem like this below:


The challenge had to have these resources below:
# Goals / Results
- Using state and localStorage
- DOM manipulation
# Requirements 📖
- Add dark-mode switching functionality to the *existing* dark-mode button
- Utilize the *existing* dark-mode SCSS file by adding a `dark-mode` class to the root `HTML` element
- When in Dark mode: The button icon should be `faSun`
- The button icon color should be `(#FFA500)`.
- You can use the `color` prop on the `Icon` component.
The start template
import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faMoon } from '@fortawesome/free-solid-svg-icons';
import '../styles/_app.scss';
function App() {
return (
<div className="app">
<div className="level">
<div>
<h1 className="title">Dark Mode</h1>
</div>
{/* --The button that should toggle dark mode-- */}
<button className="app__dark-mode-btn icon level-right">
<FontAwesomeIcon icon={faMoon} />
</button>
</div>
<div className="columns">
<div className="column">
<p>Lollipop powder powder. Cotton candy caramels chupa chups halvah muffin caramels apple pie topping cake. Topping chocolate bar pastry chocolate cake. Cupcake tart jujubes dragée jelly-o icing sugar plum. Chocolate bar lollipop candy canes. Biscuit croissant apple pie pudding caramels wafer tart tootsie roll macaroon. Croissant tiramisu chocolate bar carrot cake lemon drops halvah.</p>
</div>
<div className="column">
<p>Marshmallow tiramisu liquorice bear claw chocolate bar bear claw tart. Muffin chupa chups pie. Brownie apple pie topping lemon drops marzipan toffee. Pudding macaroon icing ice cream bonbon cake tart. Pudding sugar plum chocolate cake cake biscuit pastry pastry chocolate bar tart. Lemon drops dessert gummies icing.</p>
</div>
</div>
<div className="field">
<div className="control">
<input className="input" type="text" placeholder="Name" />
</div>
</div>
<div className="field">
<div className="control">
<input className="input" type="text" placeholder="Email" />
</div>
</div>
<section className="section">
<div className="buttons level-right">
<a className="button is-primary">Save</a>
<a className="button is-link">Submit</a>
</div>
</section>
</div>
);
}
export default App;
Considering this start template, what should you do next?
The UseState
Set an initial state as false, using useState()
import React, { useState } from 'react';
function App() {
const [darkMode, setDarkMode] = useState(false);
}
Button toggle and Ternary
Add dark-mode switching functionality to the *existing* dark-mode button;
When in Dark mode: The button icon should be `faSun` (Use Ternary).
The button icon color should be `(#FFA500)`
function App() {
return (
{/* --The button that should toggle dark mode-- */}
<button onClick={() => setDarkMode(!darkMode)} className="app__dark-mode-btn icon level-right"> <FontAwesomeIcon icon={darkMode ? faMoon : faSun} color={darkMode ? "#000" : "#FFA500"} /> </button>
}
)
}
UseEffect conditional
Utilize the *existing* dark-mode css file by adding a `dark-mode` class to the root `body` element, using conditional with useEffect()
import React, { useState, useEffect } from 'react';
function App() {
useEffect( () => {
if(darkMode) {
document.body.classList.add("dark-mode");
} else {
document.body.classList.remove("dark-mode");
}
)
}
export default App;
Plus: the LocalStorage
I used setItem() to add a value to localStorage and, to do that, I transformed data into a string.
import React, { useState, useEffect } from 'react';
function App() {
useEffect( () => {
if(darkMode) {
document.body.classList.add("dark-mode");
} else {
document.body.classList.remove("dark-mode");
}
localStorage.setItem('challenge-dark-mode', JSON.stringify(darkMode));
}, [darkMode]);
}
Then, I used again UseEffect and used getItem() to retrieve the dark info.
And to make use of it, I need to convert JSON string to JSON object using JSON.parce().
import React, { useState, useEffect } from 'react';
function App() {
useEffect(() => {
const json = JSON.parse(localStorage.getItem('challenge-dark-mode'));
if (json) {
setDarkMode(true);
} else {
setDarkMode(false);
}
}, []);
}
The complete code below:
import React from 'react';
import React, { useState, useEffect } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faMoon, faSun } from '@fortawesome/free-solid-svg-icons';
import '../styles/_app.scss';
function App() {
const [darkMode, setDarkMode] = useState(false);
useEffect(() => {
const json = JSON.parse(localStorage.getItem('challenge-dark-mode'));
if (json) {
setDarkMode(true);
} else {
setDarkMode(false);
}
}, []);
useEffect( () => {
if(darkMode) {
document.body.classList.add("dark-mode");
} else {
document.body.classList.remove("dark-mode");
}
localStorage.setItem('challenge-dark-mode', JSON.stringify(darkMode));
}, [darkMode]);
return (
<div className="app">
<div className="level">
<div>
<h1 className="title">Dark Mode Challenge</h1>
</div>
{/* --The button that should toggle dark mode-- */}
<button onClick={() => setDarkMode(!darkMode)} className="app__dark-mode-btn icon level-right">
<FontAwesomeIcon icon={darkMode ? faMoon : faSun} color={darkMode ? "#000" : "#FFA500"} />
</button>
</div>
<div className="columns">
<div className="column">
<p>Lollipop powder powder. Cotton candy caramels chupa chups halvah muffin caramels apple pie topping cake. Topping chocolate bar pastry chocolate cake. Cupcake tart jujubes dragée jelly-o icing sugar plum. Chocolate bar lollipop candy canes. Biscuit croissant apple pie pudding caramels wafer tart tootsie roll macaroon. Croissant tiramisu chocolate bar carrot cake lemon drops halvah.</p>
</div>
<div className="column">
<p>Marshmallow tiramisu liquorice bear claw chocolate bar bear claw tart. Muffin chupa chups pie. Brownie apple pie topping lemon drops marzipan toffee. Pudding macaroon icing ice cream bonbon cake tart. Pudding sugar plum chocolate cake cake biscuit pastry pastry chocolate bar tart. Lemon drops dessert gummies icing.</p>
</div>
</div>
<div className="field">
<div className="control">
<input className="input" type="text" placeholder="Name" />
</div>
</div>
<div className="field">
<div className="control">
<input className="input" type="text" placeholder="Email" />
</div>
</div>
<section className="section">
<div className="buttons level-right">
<a className="button is-primary">Save</a>
<a className="button is-link">Submit</a>
</div>
</section>
</div>
);
}
export default App;
Quite simple, isn’t it? I think that’s the right way to do it.