Dark and Light theme in any Web-App make it even more attractive. To build a theme enabled web-app in ReactJS with the help of Material-UI v5 and Redux follow this article.
Directory Structure
src
โ App.js
โ index.css
โ index.js
โ
โโโโtheme
โ โ theme.js
โ
โโโโredux
โ โ store.js
โ โ
โ โโโโtheme
โ โ themeSlice.js
Create a React Project
Using npx
create a new react project.
$ npx create-react-app my-site
Add dependencies
Add the following libraries
$ yarn add @reduxjs/toolkit react-redux @mui/material @emotion/react @emotion/styled
your package.json
should look like this
{
"name": "my-site",
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@mui/material": "^5.2.7",
"@reduxjs/toolkit": "^1.7.1",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^13.5.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.6",
"react-scripts": "5.0.0",
"web-vitals": "^2.1.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": ["react-app", "react-app/jest"]
},
"browserslist": {
"production": [">0.2%", "not dead", "not op_mini all"],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Let's Write Code ๐
Start with Writing Store / Redux
To learn the basics of the new Redux using a simple Counter App
, you may have a look at my recent article New Redux ๐ฑ is just ๐ฅ.
Create themeSlice.js
import { createSlice } from "@reduxjs/toolkit";
export const themeSlice = createSlice({
name: "theme",
initialState: {
darkTheme: false,
},
reducers: {
toggleTheme: (state) => {
state.darkTheme = !state.darkTheme;
},
},
});
export const { toggleTheme } = themeSlice.actions;
export default themeSlice.reducer;
In initialState
the default value of darkTheme
is false
, i.e. by default the theme will be light.
Register the
themeSlice
in store. So, yourstore.js
should look like this.
import { configureStore } from "@reduxjs/toolkit";
import theme from "./theme/themeSlice";
export default configureStore({
reducer: {
theme,
},
});
Don't forget to provide the store to the App in
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "./index.css";
// redux
import store from "./redux/store";
import { Provider } from "react-redux";
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
Let's write
theme/theme.js
Define both light and dark themes in theme.js
import { createTheme } from "@mui/material";
export const lightTheme = createTheme({
palette: {
mode: "light",
background: {
paper: "#f2f2f2",
},
text: {
primary: "#11111",
},
},
});
export const darkTheme = createTheme({
palette: {
mode: "dark",
background: {
paper: "#222",
},
text: {
primary: "#fff",
},
},
});
Write
App.js
Based on the Global state variable darkTheme
, provide theme to ThemeProvider HOC
.
import { useSelector, useDispatch } from "react-redux";
import { ThemeProvider } from "@mui/material/styles";
import {
Paper,
FormGroup,
FormControlLabel,
Switch,
Typography,
} from "@mui/material";
import { darkTheme, lightTheme } from "./theme/theme";
import { toggleTheme } from "./redux/theme/themeSlice";
export default function App() {
// get theme from store
const theme = useSelector((state) => state.theme);
// initialize dispatch variable
const dispatch = useDispatch();
// ToggleSwitch component
const ToggleSwitch = () => {
return (
<div
style={{
position: "absolute",
top: "10px",
right: "10px",
}}
>
<FormGroup>
<FormControlLabel
control={
<Switch
checked={theme.darkTheme}
onChange={() => dispatch(toggleTheme())}
/>
}
label="Toggle Theme"
/>
</FormGroup>
</div>
);
};
return (
<ThemeProvider theme={theme.darkTheme ? darkTheme : lightTheme}>
<Paper
style={{
minHeight: "100vh",
borderRadius: "0",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
}}
>
<ToggleSwitch />
<Typography variant="h1">Hello</Typography>
</Paper>
</ThemeProvider>
);
}
Run the Development Server ๐
$ yarn start
Light Theme
Dark Theme
Hurray! You just learned ๐ Toggle theme ๐ in React with MUI v5 and Redux ๐
I hope, you guys liked this quick tutorial. If so, then please don't forget to drop a Like โค๏ธ
And also, help me reach 1k Subscribers ๐คฉ, on my YouTube channel.
Happy Coding! ๐๐ป
Top comments (8)
Good describe, nice example. ๐คฉ๏ธ
Thank you!
A custom hook useTheme would be probably easier ๐
Do you have a link to an article describing this approach?
Not from the top of my head, but look for hooks and context.
The idea is to create a provider that will create the theme and hold the state with a method for toggling it. with that like redux, it can be called from any sub component.
For me looks like a cleaner way than setting up a redux store.
create your custom useTheme hook: youtu.be/5LrDIWkK_Bc
I'll check it out. Thanks.
Thanks, this is really helpful๐ฅ