Guide to adding a theme switcher feature to your current React website

Currently, I am faced with a challenge involving two theme files, theme.js and theme-dark.js, within the context of a complex React-based website. Despite having already set up the site, I am struggling to find a way to allow users to seamlessly switch between these two themes using a switcher integrated into the website.

The following snippet showcases how my index.js render function is structured:

const rootElement = document.getElementById('root')
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
)

Moreover, this excerpt illustrates the relevant code present in the App.tsx file:

<ThemeProvider theme={theme}>
     <CssBaseline />
     <SnackbarProvider
          .....
     </SnackbarProvider>
</ThemeProvider>

Within the App.tsx file, the above code is nested within custom Context provider components responsible for loading the initial components of the site.

Despite providing the existing code snippets above, I have hit a roadblock when attempting to incorporate a functionality allowing the user to toggle between the theme.js and theme-dark.js themes. Any guidance or assistance that can be provided would be profoundly appreciated. Unfortunately, due to security protocols at my company, I am unable to share additional code. However, it appears that the main obstacle lies in the conflict arising when introducing a custom theme provider alongside the <Provider> element in index.js.

Answer №1

To efficiently handle the job, consider implementing a simple state that can be toggled deep within your application where the switch/button is located.

While passing through with Context is an option, leveraging Redux eliminates the need to reinvent the wheel.

Start by creating a reducer for your theme type:

// isDarkModeReducer.js

export default function isDarkModeReducer(state = false, action) {
  switch (action.type) {
    case 'toggleDarkMode': {
      return !state;
    }

   default: 
    return state;
  }
}

Integrate it into your rootReducer:

// rootReducer.js
...
import isDarkModeReducer from '<location of your isDarkModeReducer reducer>';
...
const rootReducer = combineReducers({
  ...
  isDarkMode: isDarkModeReducer
})
...

In your App.tsx, retrieve the isDarkMode value from the store and apply it conditionally to load either theme.js or theme-dark.js:

// App.tsx
...
import theme from 'theme.js';
import theme-dark from 'theme-dark.js';
import { useSelector } from 'react-redux'

const isDarkMode = useSelector(state => state.isDarkMode);
...
return (
  <ThemeProvider theme={isDarkMode ? theme-dark : theme}>
     <CssBaseline />
     <SnackbarProvider
          .....
     </SnackbarProvider>
  </ThemeProvider>
);
...

To enable toggling, simply dispatch the toggleDarkMode action from wherever your switch button is positioned:

// SwitchButton
import { useDispatch } from 'react-redux'

const dispatch = useDispatch();

const toggleTheme = () => {
  dispatch({ type: 'toggleDarkMode' });
};


return (
  <button onClick={toggleTheme}>Switch Theme</button>
);

If you wish to persist the value using localStorage, refer to the instructions provided in the official documentation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Removing nested divs using JavaScript

My website has a nested div structure which contains multiple child divs. Here is an example of the div structure: <div id="outside-one"> <div class="inside" id="1"></div> <div class="inside" id="2"></div> <div ...

What is the best way to integrate a CSS designed flag in my website's top navigation bar?

My goal is to make my website multilingual, allowing users to switch between languages using flags in a dropdown menu. Initially, I tried creating the flag images solely with CSS for better resizing ability but faced difficulties. So, I resorted to using s ...

Run this command to troubleshoot errors in your React.js project

I have recently started my journey with ReactJS. The installation process went smoothly, but I encountered an error when trying to run the npm command below: me@R-SOFT-85:/var/www/reactjsbasics$ npm run build > <a href="/cdn-cgi/l/emai ...

Alert: ER_NO_SUCH_TABLE: The table 'companyapp.prescription' is not found

I am developing a basic CRUD application using React, Node.js, and Express. I have connected to my MySQL database named "managementapp" and attempted to insert information into the database. However, I keep receiving an error stating "table doesn't ex ...

The useNavigate() hook from react-router-dom is not properly setting the id in the URL path

I am currently using react-router-dom v6 for my routing needs. My goal is to pass an ID in the navigate URL path. Here is the onClick method and button code that I am working with: let navigate = useNavigate(); const routeChange = (id) => { let ...

Executing Basic Calculations Instantly with Live Data in Qualtrics

I am encountering an issue with displaying the values on a slider in Qualtrics. I need to show the value where the respondent has placed the handle, as well as the complementary value from the other end of the scale. For example, if the user has chosen 55, ...

Shifting the form to the bottom right corner

Just starting out with HTML5 and CSS, I've been experimenting with different elements. One project I've been working on is a form: <div id="form1"> <form action="demo_form.asp" autocomplete="on" > Departure City & ...

Guide on embedding a form component within an iframe using ReactJS

I am trying to figure out how to render my form component inside an iframe, but so far it's only rendering the iframe itself. Any tips on how to accomplish this task? import './App.css'; import ReactDOM from "react-dom/client" impo ...

Make TextField automatically select all text when focused

Is there a way to make a TextField in Material-UI select the entire text when clicking, tapping, or focusing on it? I have successfully implemented this functionality with an onFocus handler using event.target.select() in other React apps, but for some rea ...

const within a React component

Could someone elaborate on what occurs in line 9 of the file Wizard.js at this link: ? How does the process of unwrapping function and related details? I grasp the idea of children in React to some extent, but not in this context. When I replace <Wizar ...

Navigating a Bootstrap carousel with buttons: A step-by-step guide

Here is the code snippet I am currently working with: <!DOCTYPE html> <html> <head> <script src="https://code.jquery.com/jquery-2.1.4.js"></script> <link href="https://code.jquery.com/ui/1.11.4/them ...

Unable to serve as a JSX component. The return type 'void' is not a permissible JSX element

After creating a component called 'FormField' to streamline the code and eliminate repetition, I encountered this error message: 'FormField' cannot be used as a JSX component. Its return type 'void' is not a valid JSX element. ...

Mastering the utilization of React props within a Tailwind component

Looking to implement a straightforward button component in a Next App using Tailwind CSS, where I can pass values such as background color, text color, etc. through props and use them to render different types of buttons within my application. Take a look ...

I am feeling lost when it comes to managing state/props and making changes to the user interface in

My React app uses componentDidMount to fetch data from an external API and updates every second. I want the UI to display the current track name when it changes. While my code works fine with console logging, the UI fails to update. I am under the impress ...

Using CSS units such as vw, vh, or percentage to specify height is not possible

In my Ionic app, I am adjusting the width and height of a div based on the viewport dimensions. This setup functions correctly on the browser and Android 4.4 devices. However, it does not work as expected on Android 4.2 (the height is constrained to the te ...

Guide to utilizing Gatsby for showcasing a directory containing images and markdown files

Being new to Gatsby, react, GraphQL, and more unfamiliar technologies, I have primarily relied on pure CSS, HTML, and JavaScript for my website projects in the past. However, intrigued by the potential of Gatsby, I decided to step out of my comfort zone an ...

SyntaxError: An invalid character was encountered (at file env.js, line 1, column 1)

This marks my debut question so kindly indulge me for a moment. I recently stumbled upon a guide that outlines how to dynamically alter environment variables in a React project without the need for re-building. You can find the guide here. The method work ...

Ensure the header remains fixed when scrolling in an HTML page with Bootstrap

I created the following code. However, when I scroll down the table, the header disappears from view. I would like the header to always remain at the top, even when scrolling. Despite searching Google multiple times and trying various solutions, I have no ...

A space designated for numerous receivers

Is there a way to create a field that contains other elements, similar to sending messages to multiple users in a social network? https://i.stack.imgur.com/P9e24.png I attempted to understand the code for this, but it's quite complex. If anyone could ...

Tips for customizing the `src/app/layout.tsx` file in Next.js 13

I am looking to customize the layout for my /admin route and its child routes (including /admin/*). How can I modify the main layout only for the /admin/* routes? For example, I want the / and /profile routes to use the layout defined in src/app/layout.ts ...