Have you ever wanted to work on an app with multiple themes but don't know how to go about it? There's many ways that
Install dependency
let's get started by installing everything we'll need. For this, we will need SCSS and Redux:
yarn add sass
yarn add @reduxjs/toolkit
Simply running this script will install everything you will need and wil allow us to get started.
Part 1: Setup
SCSS
Lets start by creating a theme.scss
folder, which won't actually hold our theme, but rather all the sass vars, which we will set to css vars.
Heres the code for our theme.scss
file:
$bg1: var(--bg1);
$bg2: var(--bg2);
$bg3: var(--bg3);
$bg4: var(--bg4);
$ui1: var(--ui1);
$ui2: var(--ui2);
$ui3: var(--ui3);
$ui4: var(--ui4);
$h1: var(--h1);
$h2: var(--h2);
$p1: var(--p1);
$p2: var(--p2);
$border-rad: var(--border-rad);
$border-clr: var(--border-clr);
$font: var(--font);//etc...
this is just some starter vars for my example, but this is the premise.
now, for every .scss
file we will need to include this theme.scss
fle using @use "/path/to/theme";
Here I've created some basic code for index.scss
to add simple basic styling to all my elements, such as box-sizing
, and overriding most default margins/paddings:
@use "theme";
//--------------------
html * {
box-sizing: border-box;
margin: none;
padding: none;
justify-content: center;
align-items: center;
flex-direction: column;
font-family: theme.$font;
}
Themes
Now lets actually begin with the themes. To begin, in a new directory named themes
create a file. You can make more after, but I'll only make 2 (being dark and light) for this tutorial. You can always expand on these topics/ideas, and I completly encourage you to experiment.
Heres the basic template (this will be my dark theme):
@import url('https://fonts.cdnfonts.com/css/br-segma');
.dark {
--bg1: #202020;
--bg2: #171717;
--bg3: #131313;
--bg4: #101010;
--ui1: #252525;
--ui2: #303030;
--ui3: #353535;
--ui4: #404040;
--h1: #f5f5f5;
--h2: #f0f0f0;
--p1: #e0e0e0;
--p2: #d5d5d5;
--active: #671dc9;
--active2: #1b1fec;
--border-rad: 10px;
--border-clr: #45454590;
--font: "",sans-serif;
--color-scheme: dark;
}
And here is my light, if you're wondering:
@import url('https://fonts.cdnfonts.com/css/br-segma');
.light {
--bg1: #f0f0f0;
--bg2: #e5e5e5;
--bg3: #e0e0e0;
--bg4: #d5d5d5;
--ui1: #e2e2e2;
--ui2: #efefef;
--ui3: #f2f2f2;
--ui4: #f9f9f9;
--h1: #070707;
--h2: #101010;
--p1: #131313;
--p2: #171717;
--active: #ae70ff;
--active2: #797bff;
--border-rad: 10px;
--border-clr: #45454590;
--font: "",sans-serif;
--color-scheme: light;
}
I appended my themes to my index.scss
file, which will look like this:
@use "theme";
@use "themes/dark";
@use "themes/light";
//--------------------
//etc...
Redux
Let's get started by setting up our redux store.
In the project directory, under src, create a new folder named store
with a sub-directory named slices
. Lets begin with our store.js
file in the store
directory.
Here's what it should look like:
import { configureStore } from '@reduxjs/toolkit'
export const store=configureStore({
reducer:{
},
});
Before we get started, let's actually connect our project to redux. This is what my main.jsx
file looks like, and yours should look similar:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.jsx';
import "./index.scss";
import { store } from './store/store';
import { Provider } from 'react-redux';
createRoot(document.getElementById('root'))
.render(<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>,);
now lets create out slice. in the slices
directory create a file named themeSlice.js
.
Here is the contents:
import { createSlice } from '@reduxjs/toolkit'
export const themeSlice=createSlice({
name: 'theme',
initialState:"dark",
reducers: {
setTheme:(state,action)=>{
return action.payload;
},
},
})
export const {
setTheme
}=themeSlice.actions;
export default themeSlice.reducer;
From here, lets go back to our store and add our theme slice as a reducer.
Here's what out store.js
should look like now:
import { configureStore } from '@reduxjs/toolkit'
import ThemeReducer from "./slices/themeSlice";
export const store=configureStore({
reducer:{
theme:ThemeReducer,
},
});
Part 2: Functionality
The functionality is super simple. What we've created now is 2 classes with their own css variables, and a redux state to hold this. we can midfy our state by running dispatch(setTheme(/*theme here*/));
To apply our themes, we can use an effect to change the body's className
to our theme, and for eror protection ,we can add a check to make sure it's a valid theme and not somethine else.
Here's what that would look like:
useEffect(()=>{
switch(theme){
case "dark":
case "light":
document.body.className=theme;break;
default:
console.error("unrecognized theme");
document.body.className="dark";
}
},[theme]);
Part 3: Final
Thanks for reading!
Here is a link