Step by step guide on creating a dynamic theme in react that's color changes based on user selection

Step by step guide on creating a dynamic theme in react that's color changes based on user selection

Imagine the case that you're creating an app that is used by different companies and based on company color, your app needs to change its background and font color.

So let's create a simple react app that will have a dropdown with a list of companies, and a card with the text "John Doe's card". On change of company dropdown, header and card's background color and font color will be changed based on the selected company.

1) create a new react application with the following command.

npx create-react-app theme-app

2) After the app gets created and installing packages, clear App.css file content and keep the App.js file with the following content.

App.js

import './App.css';

function App() {
  return (
    <div className="App">
    </div>
  );
}

export default App;

3) Next write the below code to the App.js and App.css file, which will add div for header and card with design.

App.js

<div className="App">
  <div className="header">
  </div>
  <div className="content">
    <div className="card">
      <h2>John Doe's Card</h2>
    </div>
  </div>
</div>

App.css

:root {
  --backgroundColor: rgb(34, 184, 79);
  --fontColor: white;
}
.App {
  height: 100vh;
}
.header {
  height: 20%;
  width: 100%;
  background-color: var(--backgroundColor);
  display: flex;
  align-items: center;
  justify-content: center;
}
.content {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
}
.card {
  width: 40%;
  height: 100px;
  padding: 10px 20px;
  background-color: var(--backgroundColor);
  color: var(--fontColor);
  border: 2px solid black;
  border-radius: .50rem;
}

we can create CSS variables by using -- precedence and can access them anywhere with var(--name).

4) Next add a dropdown in "header", which will show a list of companies.

App.js

/* defined companies outside App component */
const companies = [
  { name: "Airbnb", backgroundColor: "rgb(247, 71, 91)", fontColor: "white" },
  { name: "Facebook", backgroundColor: "#4267b2", fontColor: "white" },
  { name: "Twitter", backgroundColor: "rgb(29, 161, 242)", fontColor: "white" },
]
/* add select inside header div */
<select>
{
  companies.map( (company,index) => 
    <option key={index} value={company.name}>{company.name}</option>
  )
}
</select>

App.css

...
select {
  width: 140px;
  height: 40px;
  outline: none;
  font-size: 18px;
}

5) Now with help of the useState hook, write logic to change variable values when the user changes company.

App.js

import React, { useState } from 'react';
const companies = [...]

function App() {
  const [ company, setCompany ] = useState(companies[0]);
  return (
    <>
      <style
        dangerouslySetInnerHTML={{ __html:`
          :root {
            --backgroundColor: ${company.backgroundColor} !important;
            --fontColor: ${company.fontColor} !important;
          }
        `}}
      />
      <div className="App">
        <div className="header">
          <select onChange={(e) => setCompany(companies.find( company => company.name === e.target.value ))}>
            ...
          </select>
        </div>
        /* content */
        ...
      </div>
    </>
  )
}

In this way, with help of CSS variables, we can Implement a global theme, that's color changes based on the user-selected option.

App.js

import React, { useState } from 'react';
import './App.css';

const companies = [
  { name: "Airbnb", backgroundColor: "rgb(247, 71, 91)", fontColor: "white" },
  { name: "Facebook", backgroundColor: "#4267b2", fontColor: "white" },
  { name: "Twitter", backgroundColor: "rgb(29, 161, 242)", fontColor: "white" },
]

function App() {
  const [ company, setCompany ] = useState(companies[0]);
  return (
    <>
      <style
        dangerouslySetInnerHTML={{ __html:`
          :root {
            --backgroundColor: ${company.backgroundColor} !important;
            --fontColor: ${company.fontColor} !important;
          }
        `}}
      />
    <div className="App">
      <div className="header">
      <select onChange={(e) => setCompany(companies.find( company => company.name === e.target.value ))}>
          {
            companies.map( (company,index) => <option key={index} value={company.name}>{company.name}</option>)
          }
        </select>
      </div>
      <div className="content">
        <div className="card">
          <h2>John Doe's Card</h2>
        </div>
      </div>
    </div>
    </>
  );
}

export default App;

App.css

:root {
  --backgroundColor: rgb(34, 184, 79);
  --fontColor: white;
}
.App {
  height: 100vh;
}
.header {
  height: 20%;
  width: 100%;
  background-color: var(--backgroundColor);
  display: flex;
  align-items: center;
  justify-content: center;
}
.content {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
}
.card {
  width: 40%;
  height: 100px;
  padding: 10px 20px;
  background-color: var(--backgroundColor);
  color: var(--fontColor);
  border: 2px solid black;
  border-radius: .50rem;
}
select {
  width: 140px;
  height: 40px;
  outline: none;
  font-size: 18px;
}