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

Using a powerful combination of Django, Django Rest Framework, and React (with TypeScript), I have created a React-Image component that beautifully displays my images in a 1295x

In my Django project, I have a hierarchy of Group, Class, Model, and Product models. These are structured in a Group{Class{Model{Product}}} format. To display this data, I created dropdown menus that function as follows: Group Checkbox |-Inner Classes ...

Modify the color of a sub division's background using CSS when hovering over

As I work on this Fiddle, my goal is to change the background of each div section individually when moused over. However, currently, hovering over one section triggers the background change for all sections. Is there a way to ensure that only the specific ...

Encountering a constructor problem while Jest is mocking a class from an NPM module

I'm currently attempting to create a mock for the Discord.JS module. Within this module, there is a Client class that I am extending in my own "Bot" class. My goal is to mock the module in order to simulate certain methods on other classes such as "Me ...

The process of React life cycle in functional components

I am new to react.js and struggling to grasp class components. The React lifecycle is something I am working hard to understand. ...

Material-UI CardMedia is experiencing difficulty in loading dynamic images from a URL, however, it is functioning properly with

I have created a function that retrieves image URLs based on the memType: const renderPicture = (memType, memID) => { if ((memType === "Music")) { toString(memID.music.map((albumArt) => (albumArt.albumArt))) } else if ((memT ...

The collaboration of TooltipClasses and FabProps is causing issues with the functionality of SpeedDialAction in Material UI React

While configuring the SpeedDial component in React's Material UI, I encountered the following requirements: Adjust the background color of the speeddial button Modify the background color of speeddialactions Change the font size of the tooltip displ ...

CrossBrowser - Obtain CSS color information

I'm attempting to retrieve the background color of an element: var bgcolor = $('.myclass').first().css('background-color') and then convert it to hex function rgbhex(color) { return "#" + $.map(color.match(/\b(\d+ ...

What is the best way to incorporate a style attribute into my EJS page content?

Having trouble with adding custom style. It seems to work, but there's an error displayed. Apologies for my poor english :( <div class="card card_applicant"> <div class="card_title" style="background-c ...

Is there a way to adjust the image opacity of a background using Material UI?

Is there a way to adjust the opacity of a background image using Material UI? I attempted to achieve this by utilizing the makeStyles hook in Material UI. Here is an example of my code: import React from 'react'; import {Box,Typography } from &ap ...

What is the recommended image size for Next.js websites?

According to documentation: The width of the image, in pixels. Must be an integer without a unit. The height of the image, in pixels. Must be an integer without a unit. https://nextjs.org/docs/api-reference/next/image Different devices come in various ...

Creating links within a single image in HTML?

Is there a way to hyperlink different parts of a single image to various webpages using JavaScript coordinates or any other method? ...

Material-UI Popover Issue: Components Causing Display Errors

I'm facing a minor issue that I can't quite pinpoint. From what I understand, React allows us to break things down into separate components, leading to cleaner pages by avoiding stuffing everything into one large HTML file. At least, that's ...

Show the bottom left quarter of the image in an HTML display

Currently, I am still new to HTML coding and experimenting with displaying specific sections of an image. The current code I have is this: <img id="theImg" style="width:100%;" src="https://'myimage.jpg'" /> I'm struggling to figure o ...

Utilize the get method to showcase data in a material UI table for a React application

Just starting out with React. Managed to create a table component with hard-coded data. However, I now have all the data stored in table.json. Can someone guide me on how to fetch values from table.json using an axios get request an ...

Issue with IE7 causing rollover navigation blocks to disappear when hovering over content

While conducting browser testing on the website The website's top navigation menu includes rollover effects for building services, exterior services, and commercial categories. The CSS-triggered navigation works seamlessly in all browsers except for ...

What is the best way to create a timer using JavaScript?

I'm looking for a reverse timer to track session timeout. I found a code on codepen that works as a clockwise timer, but my attempts to make it counterclockwise have failed. Can someone please suggest a solution? I want the timeout to be either 1 hour ...

When utilizing the ::first-letter pseudo-element on <sub> and <sup> tags

Why is the <sub> and <sup> not supporting the ::first-letter CSS pseudo-element? Any solutions? p:first-letter, sub:first-letter, sup:first-letter { color: red; font-weight: bold; } <p>This text contains <sub>subscript</su ...

jQuery functions correctly within jsfiddle, yet it encounters issues when utilized within WordPress

I've been experimenting with a jQuery script to grey out the screen. While it works perfectly on my jsFiddle link provided below, I'm having trouble getting it to work from within my WordPress plugin. Check out the working script on my jsFiddle ...

Evolution of the material through a fresh new slide

Can someone assist me with an animation issue? I have a slideshow consisting of 4 images that are supposed to transition automatically after a set time interval. Upon initially loading the webpage, the animation works perfectly as intended. However, subs ...

Troublesome situation arising from CSS floats overlapping div elements

It's strange how this issue always occurs when using floats. This is what my div (samle) looks like: <div class="main> <div class="inn_div">&nbsp</div> </div> Here is my stylesheet: .main{ width:250px; border:1px ...