Creating Theme Systems in React with SCSS and Redux

M1dnightGMR - Nov 6 - - Dev Community

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
Enter fullscreen mode Exit fullscreen mode

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...
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode
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;
}
Enter fullscreen mode Exit fullscreen mode

I appended my themes to my index.scss file, which will look like this:

@use "theme";
@use "themes/dark";
@use "themes/light";
//--------------------
//etc...
Enter fullscreen mode Exit fullscreen mode

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:{

  },
});
Enter fullscreen mode Exit fullscreen mode

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>,);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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,
  },
});
Enter fullscreen mode Exit fullscreen mode

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]);
Enter fullscreen mode Exit fullscreen mode

Part 3: Final

Thanks for reading!
Here is a link

.
Terabox Video Player