Theming in React with Styled Components

Published on Mar 14, 2021
~11 min read

Theming, what the hell is it and how can we use it to make awesome web experiences.

A Theme is a preset package of graphical features like colors, fonts and buttons. Theming is storing these features in an application so that we can maintain a consistent theme across our application and until I started my internship a week ago I had no idea it existed.

I've quickly learnt from my internship that theming is used to maintain style consistency in applications and by doing so it helps to create great user experiences. Imagine that you are using a website, and the font changes style from paragraph to paragraph or it is sized different depending on what article you are reading does that sound like a good experience? Hell no.

So theming is used to help maintain consistency and recently it has been used to allow websites to easily implement things like dark mode.

In this article we are going to learn how to set up theming with styled components in React to make an awesome 90's mode theme we can toggle from our original minimal theme as Dark mode is so 2020.

Let's kick it off with the set up of our application.

Setup - Theming in React

If you've set up React Projects before you can skip most of this section, just make sure you have the dependencies installed. Otherwise follow along and we'll get it ready to go for the fun part.

We need to set up the project with React and Styled Components. To do that, we need to use [create-react-app](https://create-react-app.dev/).

Open up your terminal and use this command to create a project:

ZSH
npx create-react-app theming-tutorial

The last argument, theming-tutorial, is just the name of the project which is set up as a folder for us. We could have called it anything for example 'rosebud' or 'broccoli'.

It will take a few minutes so grab a coffee and continue once it's done.

Now we need to navigate to the folder 'theming-tutorial' using the command cd theming-tutorial. In that folder is a file located in the src folder called App.js. Open that file either using the code editor of your choice or by typing open src/App.js and replace all of the content with the below.

JSX
import React from "react";
function App() {
return (
<div>
<header>
<button>Toggle Theme</button>
</header>
<div className="hero">
<div className="hero-container">
<div className="text-container">
<h1>Theming Tutorial</h1>
<p>
Darkmode been there done that, cyberpunk mode is where is is at.
</p>
</div>
<div className="image-container">
<img
src="https://images.theconversation.com/files/65451/original/image-20141125-2362-1h3qjuh.jpg?ixlib=rb-1.1.0&q=45&auto=format&w=1200&h=1200.0&fit=crop"
alt="futuristic city"
/>
<div className="corner-br"></div>
</div>
</div>
</div>
</div>
);
}
export default App;

You will also need to clear everything out of the App.css and replace it with the following:

CSS
header {
float: right;
}
.hero {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.hero-container {
display: flex;
justify-content: space-around;
align-items: center;
width: 90vw;
margin: 0 auto;
}
.text-container {
display: flex;
flex-direction: column;
}
h1 {
margin: 0;
}
img {
width: 400px;
height: 300px;
}

This is a bare bones basic React component that we are going to modify to make our awesome nineties mode theme.

In your terminal run either of the following commands to open the application depending on whether you use npm or yarn (yarn for life!).

ZSH
npm run start
##or
yarn start

You can now access the app in your browser with the URL `http://localhost:3000`.

Dependencies

Next we need to install our styled-components dependency for our application again either using npm or yarn.

BASH
npm install styled-components
yarn add styled-components

Doing so gives us styled-components. Styled-components are a flexible way to style React components with CSS. What it gives us that is really awesome for this project is out-of-the-box theming support. It does this with a wrapper component called ThemeProvider. This component gives the theme to all our other components that are wrapped within it. This will make more sense in a minute when we see it in action.

Before we jump into the tutorial section it is worth explaining a little bit on what styled components are. Put simply, styled components are a way to compartmentalise our CSS styles to individual components.

This prevents style and naming clashes, which is a huge benefit.

Another big benefit is it allows us to use props so we can pass dynamic values to it.

Now we are all set to get into actually making our cyberpunk mode effect.

Theming Tutorial

The are four key things we are going to need to create our 90's theme toggle:

  1. Theme file - this will hold all the properties for our minimal and our 90's themes.
  2. GlobalStyle - this is where we store the global styles for the entire application.
  3. Toggler - this is the element users will see on the page to switch between themes.
  4. Custom Hook useCyberpunkMode - this custom hook will handle the logic behind the change of theme and the persistence of our theme in local storage.

Before we get to making the Theme file we need to create a `Styles` folder in our `src` folder. Once we have that we can get into theming.

Theme

Ok, within our Styles folder we need to create a Theme.js file, then we are going to add the code below.

JS
export const minimalTheme = {
body: "#192E40",
textColor: "#fefefe",
font: "Tahoma, Helvetica, Arial, Roboto, sans-serif",
toggleBorder: "#5F88D9",
imageCorner: "0",
imageBorder: "none",
};
export const cyberpunkTheme = {
body: "#fcee0a",
textColor: "#05080D",
font: "font-family: 'Maven Pro', sans-serif",
toggleBorder: "#BF1792",
imageCorner: "1",
imageBorder: "#5cdcf6",
};

Here we have defined and exported our minimalTheme and cyberpunkTheme objects with our color variables for each them. Notice that we have named the keys the same in both objects but are changing the values. By having the same key names we can easily toggle between the two styles which will become more obvious in a minute.

Global Styles Component

Next up we need to create a globalStyle.js file in our Styles folder. We then need to add the following code to the file.

JSX
import { createGlobalStyle } from "styled-components";
export const GlobalStyles = createGlobalStyle`
@import url('https://fonts.googleapis.com/css2?family=Maven+Pro:wght@400;700&display=swap');
body {
background: ${({ theme }) => theme.body};
color: ${({ theme }) => theme.textColor};
font-family: ${({ theme }) => theme.font};
transition: all 0.50s linear;
}
// image styling
.image-container {
position: relative;
img {
position: relative;
border-right: 3px solid ${({ theme }) => theme.imageBorder};
border-bottom: 3px solid ${({ theme }) => theme.imageBorder};
}
.corner-br {
position: absolute;
left: 0;
top: 0;
width: 0;
height: 0;
border-color: ${({ theme }) => theme.body} transparent transparent;
border-style: solid;
border-width: 17px 17px 0 0;
opacity: ${({ theme }) => theme.imageCorner};
}
}
`;

Let's run through what is happening here. Firstly we imported createGlobalStyle from the styled components libary, this is a helper function which will handle global styles for us. As the styled components API referenene explains normally, styled components are automatically scoped to a local CSS class and therefore isolated from other components. In the case of createGlobalStyle, this limitation is removed and things like CSS resets or base stylesheets can be applied. This method is going to let you inject your global styles into the document, which in this instance will be injected into our App.js.

In our GlobalStyles component we have defined what the background and color will be for the body of the application by using props ${({ theme }) ⇒ theme.body}. The theme.body refers to the variable named body in the Theme.js file.

The transition property is just for visual effect to make the change between thems appear smooth.

We also have some theming props on the image to style it more cyberpunk style, you'll se what I mean when we start toggling.

Now that we have our themes and our smooth transition we need to create the functionality that will allow use to toggle between the themes.

Theme toggling and Custom Hook

Okay to allow users to toggle between themes we need to add some functionality to do so. We are going to do this in a customer hook to keep our React code scalable.

But first we need to set up our App.js file so it can handle the change.

JSX
import React from "react";
import { ThemeProvider } from "styled-components";
import { GlobalStyles } from "./Styles/Globalstyle";
import { minimalTheme, cyberpunkTheme } from "./Styles/Themes";
import "./App.css";
const App = () => {
return (
<ThemeProvider>
<>
<GlobalStyles />
<div>...</div>
</>
</ThemeProvider>
);
};
export default App;

Breaking down what is happening above we have imported the ThemeProvider from styled-components, this function helper supports theming. Basically what it does is allow all styled components to have access to the themes we created in the themes file. It does this by wrapping everything in our apps return statement and it injects the theme into all styled components anywhere beneath it.

On the next line we import the GlobalStyle wrapper from ./components/Globalstyle. Then one line below we import both the minimal theme and cyberpunk theme objects from ./components/Themes.

Alright now to help make our App scalable we want to create a new component useCyberpunkMode and then write a custom hook.

To do this create a new folder in the src folder and name it Components. The create the useCyberpunkMode.js file. Then enter the code below into the file.

JSX
import { useEffect, useState } from "react";
export const useCyberpunkMode = () => {
const [theme, setTheme] = useState("minimal");
const setMode = (mode) => {
window.localStorage.setItem("theme", mode);
setTheme(mode);
};
const themeToggler = () => {
theme === "minimal" ? setMode("cyberpunk") : setMode("minimal");
};
useEffect(() => {
const localTheme = window.localStorage.getItem("theme");
localTheme && setTheme(localTheme);
}, []);
return [theme, themeToggler];
};

First we define the component useCyberpunkMode. Then we set the state using hooks. We have set the theme state as minimal our default theme. Meaning the first time a user visits our app they will see the minimal theme.

Next we create a setMode function. This function stores the theme in the browsers local storage, what this means is that the users theme that they are using on our site will persist across sessions. In simpler terms if the user sets it to cyberpunk theme and they close the tab, when they come back it will still be the cyberpunk theme. It does this by setting the state and passing the theme to local storage.

The next function we define is themeToggler this function uses a ternary operator to check that state of the theme and toggles either cyberpunk of minimal pending which theme is currently on the browsers window.

Finally the useEffect hook checks to see if the user has previously selected a theme, if the theme has been selected we use inline If with `&&` so it is saying if localTheme exists (that is it is true) then we use our custom hook to set the theme as what was stored in local storage.

Now we can update our App.js file to take advantage of our new customer hook.

JSX
import { ThemeProvider } from "styled-components";
import { GlobalStyles } from "./Styles/GlobalStyles";
import { minimalTheme, cyberpunkTheme } from "./Styles/Themes";
import "./App.css";
import { useCyberpunkMode } from "./Components/useCyberpunkMode";
function App() {
const [theme, themeToggler] = useCyberpunkMode();
const themeMode = theme === "minimal" ? minimalTheme : cyberpunkTheme;
return (
<ThemeProvider theme={themeMode}>
<GlobalStyles />
<div>
<header>
<button onClick={themeToggler}>Toggle Theme</button>
</header>
<div className="hero">
<div className="hero-container">
<div className="text-container">
<h1>Theming Tutorial</h1>
<p>
Darkmode been there done that, cyberpunk mode is where is is at.
</p>
</div>
<div className="image-container">
<img
src="https://images.theconversation.com/files/65451/original/image-20141125-2362-1h3qjuh.jpg?ixlib=rb-1.1.0&q=45&auto=format&w=1200&h=1200.0&fit=crop"
alt="futuristic city"
/>
<div className="corner-br"></div>
</div>
</div>
</div>
</div>
</ThemeProvider>
);
}
export default App;

Now we import our custom hook and destructure the theme and themeToggler props, and set it with the useCyberpunkMode function.

Let's try and toggle this bad boy.

theming demo in react with styled components

Now there you have it, your very own cyberpunk theming website built in React with styled components.

I you have any questions on the build reach out to me on my twitter here.

Picture of author

Peter Lynch

Web Developer & Bootcamp grad who wants to learn as much as he can check me out on twitter.

Starting from the bottom newsletter

This newsletter is a record of my journey as an indie hacker, developer, entrepreneur, and human. Delivered straight to your inbox each Sunday.