The nested ThemeProvider takes priority over the theme's style definitions

Is there a way to render a component and then apply additional rendering using useEffects in React?

The issue I am facing is that when I have a component with a specific theme, each useEffect call ends up overriding the style of the original component with its own theme.

I am using React 17.0.2 and material-ui 4.12.4 for this scenario. Below is the relevant code snippet:

import React from "react";
import ReactDOM from "react-dom";

import { createTheme, ThemeProvider } from "@material-ui/core/styles";
import CssBaseline from "@material-ui/core/CssBaseline";

import orange from "@material-ui/core/colors/orange";
import green from "@material-ui/core/colors/green";
import Checkbox from "@material-ui/core/Checkbox";
import Person from "@material-ui/icons/Person";

const greenTheme = createTheme({
  palette: {
    secondary: {
      main: green[500]
    }
  }
});

const orangeTheme = createTheme({
  palette: {
    secondary: {
      main: orange[500]
    }
  }
});

function App() {
  React.useEffect(() => {
    const div = document.createElement("div");
    div.style.backgroundColor = "#ccc";

    ReactDOM.render(
      <ThemeProvider theme={greenTheme}>
        <CssBaseline />
        <div>
          <Checkbox defaultChecked />
          <Person color="secondary" />
        </div>
      </ThemeProvider>
      , div
    );

    document.getElementById("root").append(div);
  });

  React.useEffect(() => {
    const div = document.createElement("div");
    div.style.backgroundColor = "#ccc";

    ReactDOM.render(
      <ThemeProvider theme={orangeTheme}>
        <CssBaseline />
        <div>
          <Checkbox defaultChecked />
          <Person color="secondary" />
        </div>
      </ThemeProvider>
      , div
    );

    document.getElementById("root").append(div);
  });

  return (
    <ThemeProvider theme={greenTheme}>
      <CssBaseline />
      <Checkbox defaultChecked />
      <Person color="secondary" />
      <div>
        The color of above icon should be green but is getting overriden
      </div>
    </ThemeProvider>
  );
}

export default App;

https://codesandbox.io/s/material-nested-themes-demo-forked-1zvv8r?fontsize=14&hidenavigation=1&theme=dark

Answer №1

Your approach to rendering inside effects seems unusual. I can't identify a reason for doing it that way. Would it be possible to consider an alternative method like the following instead?

import React from "react";
import ReactDOM from "react-dom";

import { createTheme, ThemeProvider } from "@material-ui/core/styles";
import CssBaseline from "@material-ui/core/CssBaseline";

import orange from "@material-ui/core/colors/orange";
import green from "@material-ui/core/colors/green";
import Checkbox from "@material-ui/core/Checkbox";
import Person from "@material-ui/icons/Person";

const greenTheme = createTheme({
  palette: {
    secondary: {
      main: green[500]
    }
  }
});

const orangeTheme = createTheme({
  palette: {
    secondary: {
      main: orange[500]
    }
  }
});

function Div1() {
  return (
    <div style={{backgroundColor: "#ccc"}}>
      <ThemeProvider theme={greenTheme}>
        <CssBaseline />
        <div>
          <Checkbox defaultChecked />
          <Person color="secondary" />
        </div>
      </ThemeProvider>
    </div>
  );
}

function Div2() {
  return (
    <div style={{backgroundColor: "#ccc"}}>
      <ThemeProvider theme={orangeTheme}>
        <CssBaseline />
        <div>
          <Checkbox defaultChecked />
          <Person color="secondary" />
        </div>
      </ThemeProvider>
    </div>
  );
}

function App() {
  return (
    <>
      <ThemeProvider theme={greenTheme}>
        <CssBaseline />
        <Checkbox defaultChecked />
        <Person color="secondary" />
        <div>
          The color of above icon should be green but is getting overriden
        </div>
      </ThemeProvider>
      <Div1 />
      <Div2 />
    </>
  );
}

export default App;

This suggested approach separates each div into its own component, making it easier to manage and render them in a more conventional manner. If you prefer having them as sibling elements to the ThemeProvider within the App component, you can easily achieve this by adjusting the jsx structure. Simply utilize fragments (<></>) to ensure that each function returns only one element.

Answer №2

In response to my own inquiry, after reviewing the feedback in https://github.com/mui/material-ui/issues/15914 it is recommended that the <ThemeProvider> should be enclosed within a <StyleProvider>.

Therefore, the updated code would look like this:

      <StylesProvider generateClassName={generateClassName("a")}>
        <ThemeProvider theme={orangeTheme}>
          <CssBaseline />
          <div>
            <Checkbox defaultChecked />
            <Person color="secondary" />
          </div>
        </ThemeProvider>
      </StylesProvider>,

With these adjustments, the colors now display correctly without any style inconsistencies.

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

How can I adjust the container to fit the monitor's dimensions while still keeping the

I am currently facing an issue on my website where the main content div has a fixed height, causing it not to scale vertically on larger monitors. I attempted setting the CSS properties for the div to 'auto' in order to allow it to adjust to the ...

ReactJS how to prevent accordion from collapsing automatically

My custom accordion layout for the features needed in the site I am building is not working well with Jquery. How can I modify it to collapse properly? Specifically, I want it so that when I open number 2, number 1 will automatically close. I've trie ...

Dealing with Numerous Checkboxes using Material UI and Formik

I'm working on a form that includes a checkbox group with 4 checkboxes. My goal is to pass these values to an API upon submitting the form using Formik. There are specific conditions based on which checkboxes are checked: If the 'Height' c ...

The data type 'string' cannot be assigned to the data type 'Position'

Currently, I am in the process of converting React js to typescript. The component being used is a Class Component. I would like to obtain CSS settings through props and apply them to an element. How can I resolve this issue? render(){return( <span st ...

Stylized widget for showcasing a list of cities for meetups

After extensive searching, I have yet to find a solution to stylize the "City List" widget for Meetup. The specific widget I am focusing on is the first one listed here. () Despite exploring various options such as the widget foundry and conducting onlin ...

Is it possible for a search box selection toggle to reveal a hidden information box underneath it containing all the compiled data?

Improve the user experience on my website by implementing a search feature for US states and Canadian territories. When visitors type in their selection, I want them to be able to click on an icon that will reveal relevant information about that choice. T ...

Troubleshooting a CSS problem on a table filled with images - See attached screenshots for

I've been working on a project involving my phpmyadmin database generating a series of 6 images on my website. I've placed them in a table, but now I'm facing some challenges - even though it seemed simple at first! The goal is to display t ...

Error: TokenSet is missing the access_token field

My current project involves creating a blogsite with authentication set up using auth0 and express for the backend. React is being utilized for the client side. In order to access information about the logged in user, I need to send the req.oidc.fetchUserI ...

"Exploring the versatility of Tailwind css: A guide to implementing multiple themes

I know how to customize dark and light themes in tailwind, but I'm curious about extending this functionality to include additional themes such as pink, blue, red, etc. Is there a way to achieve this with regular tailwind CSS? <p className="t ...

What is the best way to eliminate HTML <li> bullets using codebehind?

When working in codebehind, I often create an HTML list using the following method: HtmlGenericControl list = new HtmlGenericControl("ul"); for (int i = 0; i < 10; i++) { HtmlGenericControl listItem = new HtmlGenericControl("li"); Label textLabel ...

Getting Started with Styling in React Using Styled Components

I seem to be having trouble with styled components; something must be off in my setup. Here's the component I'm working with: import React from 'react'; import styled from 'styled-components'; const Wrapper = styled.div` d ...

Having difficulties with Cypress test for dragging and dropping an element within the same area

I am experimenting with the drag and drop feature using a plugin called 4teamwork/cypress-drag-drop. I have a scenario where there are three elements stacked on top of each other. The task is to select the first element and move it under the last element i ...

Transform your current website layout from a fixed 960-grid system with 12 columns into a fluid and

As a newcomer to web development, I have successfully created my portfolio website. I initially set the body width to 1600px because that matched the size of my banner background in Photoshop. I'm using a 960gs 12-column grid system, but when I view t ...

Whenever I navigate to a new page in my NEXTJS project, it loads an excessive number of modules

I am currently working on a small Next.js project and facing an issue where the initial load time is excessively long. Whenever I click on a link to navigate to a page like home/product/[slug], it takes around 12 seconds to load due to compiling over 2000 ...

Display/conceal within a jQuery fixed navigation bar (center-aligned)

I am facing challenges with creating a sticky menu that shows/hides with a click button. Considering abandoning the show/hide feature altogether and rebuilding it from scratch in the future. Two major problems I have identified: How can I make the sho ...

Vertical spacing on elements utilizing a position of absolute

Looking to create vertical space for elements with position:absolute and changing heights using just CSS. Any clever techniques involving containers or display properties that could be helpful? ...

Is there a solution to the Chrome issue "Require user interaction for beforeunload dialogs" that arises while running Cypress tests?

Require user gesture for beforeunload dialogs A new feature has been implemented where the beforeunload dialog will only be displayed if the frame attempting to show it has received a user gesture or interaction, or if any embedded frame has received su ...

Which is better: NextJs or just pure ReactJs?

Although I recognize the advantages of NextJs such as SSR (which supports SEO), built-in routing, and image rendering optimization, it seems that using a state management library like Redux or Thunk is still necessary for managing app-wide state. While the ...

Attempting to initialize 'awsmobile init' for a web React project is proving to be unsuccessful

Following the AWS Documentation instructions, I created a hello-world react app. However, when attempting to run the "awsmobile init" command in the app root folder, I encountered an error stating 'Unexpected token function'. My current node ver ...

TS7053: The element is implicitly assigned an 'any' type as the expression of type 'string' cannot be used to index the type '{ username: string; email: string; '

Having trouble incorporating TypeScript into a custom React Form Component, and I keep encountering an error that I can't seem to resolve. Error message TS7053: Element implicitly has an 'any' type because expression of type 'string&apo ...