Recently, I took over a project that requires support for theme features on the website. This is a bit strange requirement, as this application is mainly used by a few administrators. Even more surprising is that they want to choose not only between pre-created topics, but also create their own . I think people want whatever they want!
Let's distill this into a more detailed list of requirements and finish it!
- Define a theme (such as background color, font color, button, link, etc.)
- Create and save multiple topics
- Select and apply topics
- Switch theme
- Custom theme
We delivered the product exactly as the customer’s requirements and as far as I know, they are using it very happily now!
Let's start building this feature. We will use React and styled-components. All the source code used in this article can be found in the GitHub repository.
View Demo### Settings
Let's set up a project with React and styled-components. To do this, we will use create-react-app. It provides us with the running environment we need to quickly develop and test React applications.
Open a command prompt and create a project with the following command:
<code>npx create-react-app theme-builder</code>
The last parameter theme-builder is just the project name (and the folder name). You can use any name you like.
This can take a while. Once done, use cd theme-builder to navigate to it on the command line. Open the file src/App.js and replace its content with the following:
<code>import React from 'react'; function App() { return (</code> Theme builder ); } export default App;
This is a basic React component that we will modify soon. Start the application from the project root folder:
<code># 或npm run start yarn start</code>
You can now use the URL https://www.php.cn/link/cc685cba3900c73c40533b18e15b66e5 .
create-react-app comes with test files for the App component. Since we won't write any tests for components in this article, you have the option to delete the file.
We have to install some dependencies for our application. So let's install them by the way:
<code># 或npm i ... yarn add styled-components webfontloader lodash</code>
Here is what we got:
- styled-components: A flexible way to style React components using CSS. It provides out-of-the-box theme support using a named
<themeprovider></themeprovider>
wrapper component. This component is responsible for providing the theme to all other React components wrapped inside it. We will see its practical application soon. - Web Font Loader: Web Font Loader helps load fonts from various sources, such as Google Fonts, Adobe Fonts, etc. We will use this library to load fonts when applying the theme.
- lodash: This is a JavaScript utility library that provides some convenient gadgets.
Define the topic
This is our first requirement. The theme should have a certain structure to define the appearance, including colors, fonts, etc. For our application, we will define each topic using the following properties:
- Unique identifier
- Subject name
- Color definition
- Font
You may have more properties and/or different structures, but these are what we will use in our example.
Create and save multiple topics
So, we just saw how to define a topic. Now let's create multiple themes by adding a src/theme folder and a file named schema.json in the project. Here is what we can put into this file to create the "light" and "wave" themes:
<code>{ "data" : { "light" : { "id": "T_001", "name": "浅色", "colors": { "body": "#FFFFFF", "text": "#000000", "button": { "text": "#FFFFFF", "background": "#000000" }, "link": { "text": "teal", "opacity": 1 } }, "font": "Tinos" }, "seaWave" : { "id": "T_007", "name": "海浪", "colors": { "body": "#9be7ff", "text": "#0d47a1", "button": { "text": "#ffffff", "background": "#0d47a1" }, "link": { "text": "#0d47a1", "opacity": 0.8 } }, "font": "Ubuntu" } } }</code>
The contents of the schema.json file can be saved to the database so that we can persist all topics and topic selections. Currently, we just need to store it in the browser's localStorage. To do this, we will create a new file named storage.js in src/utils. We only need a few lines of code to set up localStorage:
<code>export const setToLS = (key, value) => { window.localStorage.setItem(key, JSON.stringify(value)); } export const getFromLS = key => { const value = window.localStorage.getItem(key); if (value) { return JSON.parse(value); } }</code>
These are simple utility functions for storing data to and retrieving data from the browser's localStorage. Now, we will load the topic into the browser's localStorage when we launch the app for the first time. To do this, open the index.js file and replace the content with the following:
<code>import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import * as themes from './theme/schema.json'; import { setToLS } from './utils/storage'; const Index = () => { setToLS('all-themes', themes.default); return(<app></app> ) } ReactDOM.render(<index></index> , document.getElementById('root'), );</code>
Here we get the topic information from the schema.json file and add it to localStorage using the key all-themes. If you have stopped running the application, start it again and access the UI. You can use DevTools in your browser to see if the topic is loaded into localStorage.
Select and apply topics
We can now use the theme structure and provide the theme object to<themeprovider></themeprovider>
Wrapper.
First, we will create a custom React hook. This will manage the selected topic to see if the topic is loaded correctly or if there are any problems. Let's start with a new file named useTheme.js in the src/theme folder, which contains the following:
import { useEffect, useState } from 'react'; import { setToLS, getFromLS } from '../utils/storage'; import _ from 'lodash'; export const useTheme = () => { const themes = getFromLS('all-themes'); const [theme, setTheme] = useState(themes.data.light); const [themeLoaded, setThemeLoaded] = useState(false); const setMode = mode => { setToLS('theme', mode) setTheme(mode); }; const getFonts = () => { const allFonts = _.values(_.mapValues(themes.data, 'font')); return allFonts; } useEffect(() =>{ const localTheme = getFromLS('theme'); localTheme ? setTheme(localTheme) : setTheme(themes.data.light); setThemeLoaded(true); }, []); return { theme, themeLoaded, setMode, getFonts }; };
This custom React hook returns the selected topic from localStorage and a boolean value to indicate whether the topic has been loaded correctly from storage. It also exposes a function setMode for applying a theme programmatically. We'll get back to this later. With this we can also get a list of fonts that can be loaded later using the webfontloader.
Using global styles to control the background color, font, buttons, etc. of your website will be a good idea. styled-components provides a component called createGlobalStyle to establish a global component that is subject-aware. Let's create a file named GlobalStyles.js in the src/theme folder with the following code:
import { createGlobalStyle} from "styled-components"; export const GlobalStyles = createGlobalStyle` body { background: ${({ theme }) => theme.colors.body}; color: ${({ theme }) => theme.colors.text}; font-family: ${({ theme }) => theme.font}; transition: all 0.50s linear; } a { color: ${({ theme }) => theme.colors.link.text}; cursor: pointer; } button { border: 0; display: inline-block; padding: 12px 24px; font-size: 14px; border-radius: 4px; margin-top: 5px; cursor: pointer; background-color: #1064EA; color: #FFFFF; font-family: ${({ theme }) => theme.font}; } button.btn { background-color: ${({ theme }) => theme.colors.button.background}; color: ${({ theme }) => theme.colors.button.text}; } `;
Just for Some CSS for , links and buttons, right? We can use these for the App.js file to see the actual effect of the theme by replacing the content in it with this:
// 1: Import import React, { useState, useEffect } from 'react'; import styled, { ThemeProvider } from "styled-components"; import WebFont from 'webfontloader'; import { GlobalStyles } from './theme/GlobalStyles'; import {useTheme} from './theme/useTheme'; // 2: Create a container const Container = styled.div` margin: 5px auto 5px auto; `; function App() { // 3: Get selected topics, font lists, etc. const {theme, themeLoaded, getFonts} = useTheme(); const [selectedTheme, setSelectedTheme] = useState(theme); useEffect(() => { setSelectedTheme(theme); }, [themeLoaded]); // 4: Load all fonts useEffect(() => { WebFont.load({ google: { families: getFonts() } }); }); // 5: Render if the theme is loaded. Return ( <themeprovider theme="{selectedTheme}"> <globalstyles></globalstyles> <container> <h1 id="Theme-builder">Theme builder</h1> <p> This is a theme system with theme switcher and theme builder. Do you want to view the source code? <a href="https://www.php.cn/link/e5a419ed77a4e034849e1e1b68ba015e" target="_blank">Click here.</a> </p> </container> </themeprovider> ); } export default App;
Something happened here:
- We import useState and useEffect React hooks , which will help us track any state variables and their changes due to any side effects. We import ThemeProvider and styled from styled-components. WebFont is also imported to load fonts. We also import custom theme useTheme and global style component GlobalStyles.
- We use CSS style and styled components to create a Container component .
- We declare state variables and pay attention to changes.
- We load all the fonts we need for the application .
- We render a bunch of text and a link. But please note that we use the selected topic as prop
<themeprovider></themeprovider>
The wrapper wraps the entire content. We also passed<globalstyles></globalstyles>
Components.
Refresh the app and we should see the default "light color" theme enabled.
We should see if switching themes works. So let's open the useTheme.js file and change this line:
localTheme ? setTheme(localTheme) : setTheme(themes.data.light);
……arrive:
localTheme ? setTheme(localTheme) : setTheme(themes.data.seaWave);
Refresh the app again, hoping we can see the actual effect of the "Waves" theme.
Switch theme
Very good! We are able to apply the topic correctly. So, how about switching themes with just one button? Of course we can do it! We can also provide some kind of theme preview.
Let's call each of these boxes ThemeCard and set them in a way that they can have their theme definitions as props. We will iterate through all the themes, loop through them, and fill each theme with the ThemeCard component.
{ themes.length > 0 && themes.map(theme =>( <themecard key="{theme.id}" theme="{theme}"></themecard> )) }
Now let's turn to ThemeCard's mark. Your markup may look different, but note how we extract their own color and font properties and then apply them:
const ThemeCard = props => { return( <wrapper style="{{backgroundColor:" fontfamily:> Click the button to set this topic<themebutton onclick="{()"> themeSwitcher(props.theme)} style={{backgroundColor: `${props.theme.colors.button.background}`, color: `${props.theme.colors.button.text}`, fontFamily: `${props.theme.font}`}}> {props.theme.name} </themebutton> </wrapper> ) }
Next, let's create a file named ThemeSelector.js in the src folder. Copy the content here and put it into a file to build our theme switcher, we need to import it in App.js:
import ThemeSelector from './ThemeSelector';
Now we can use it in the Container component:
<container> {/* Same as before*/} <themeselector setselectedtheme="{setMode}" themes="{themes.data}"></themeselector> </container>
Now let's refresh the browser and see how switching themes work.
Interestingly, you can add as many themes as you want in the schema.json file to load them in the UI and switch. Check out this schema.json file for more topics. Please note that we also save the application's theme information in localStorage, so the next time we reopen the application, the selection will be retained.
Custom theme
Maybe your users like certain aspects of one topic and certain aspects of another topic. Why let them choose between the two when they can give themselves the ability to define subject properties! We can create a simple user interface that allows users to select the display options they want, and even save their preferences.
We won't go into details about the explanation of the topic creation code, but by following the code in GitHub Repo, this should be easy. The main source file is CreateThemeContent.js, which is used by App.js. We create a new theme object by collecting the values of each input element change event and add that object to the theme object collection. That's it.
Before we end...
Thank you for reading! I hope you find what we've covered here useful for what you're working on. Theme system is very interesting! In fact, CSS custom properties are making it increasingly a thing. For example, check out this approach to color by Dieter Raber and this review by Chris. This setting for Michelle Barker also relies on custom properties used with Tailwind CSS. This is another way of Andrés Galente.
All of these are great examples of creating themes, and I hope this article can help take this concept to the next level by storing properties, easily switching between themes, enabling users to customize themes, and saving these preferences.
Let's contact us! You can send me comments via DM on Twitter, or follow me at will.
The above is the detailed content of Theming and Theme Switching with React and styled-components. For more information, please follow other related articles on the PHP Chinese website!

Yes,youshouldlearnbothFlexboxandGrid.1)Flexboxisidealforone-dimensional,flexiblelayoutslikenavigationmenus.2)Gridexcelsintwo-dimensional,complexdesignssuchasmagazinelayouts.3)Combiningbothenhanceslayoutflexibilityandresponsiveness,allowingforstructur

What does it look like to refactor your own code? John Rhea picks apart an old CSS animation he wrote and walks through the thought process of optimizing it.

CSSanimationsarenotinherentlyhardbutrequirepracticeandunderstandingofCSSpropertiesandtimingfunctions.1)Startwithsimpleanimationslikescalingabuttononhoverusingkeyframes.2)Useeasingfunctionslikecubic-bezierfornaturaleffects,suchasabounceanimation.3)For

@keyframesispopularduetoitsversatilityandpowerincreatingsmoothCSSanimations.Keytricksinclude:1)Definingsmoothtransitionsbetweenstates,2)Animatingmultiplepropertiessimultaneously,3)Usingvendorprefixesforbrowsercompatibility,4)CombiningwithJavaScriptfo

CSSCountersareusedtomanageautomaticnumberinginwebdesigns.1)Theycanbeusedfortablesofcontents,listitems,andcustomnumbering.2)Advancedusesincludenestednumberingsystems.3)Challengesincludebrowsercompatibilityandperformanceissues.4)Creativeusesinvolvecust

Using scroll shadows, especially for mobile devices, is a subtle bit of UX that Chris has covered before. Geoff covered a newer approach that uses the animation-timeline property. Here’s yet another way.

Let’s run through a quick refresher. Image maps date all the way back to HTML 3.2, where, first, server-side maps and then client-side maps defined clickable regions over an image using map and area elements.

The State of Devs survey is now open to participation, and unlike previous surveys it covers everything except code: career, workplace, but also health, hobbies, and more.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

Atom editor mac version download
The most popular open source editor

DVWA
Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

WebStorm Mac version
Useful JavaScript development tools

EditPlus Chinese cracked version
Small size, syntax highlighting, does not support code prompt function
