27
votes

I'm trying something very simple: building two themes for a website using Material-UI themes:

A light theme and dark one, but it does not work well: the theme is on every Material-UI react element, but the root element on the html document keeps having the same default white background.

Of course it can be changed by attacking the body with pure .css:

body {
  background-color: #222;
}

But I was looking to change it dynamically with React, I though this would work, but it does not:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { ThemeProvider } from '@material-ui/styles';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';

const themeLight = createMuiTheme({
  palette: {
    background: {
      default: "#e4f0e2"
    }

    },
});

const themeDark = createMuiTheme({
    palette: {
      background: {
        default: "#222222",
      }

    },
});

ReactDOM.render(
     <MuiThemeProvider theme = { themeDark }>
      <App />
     </MuiThemeProvider>, document.getElementById('root'));

and I'm lost here, there is no way to make this with Material-UI theme?

4

4 Answers

45
votes

CssBaseline is the component that controls this aspect. If you aren't using CssBaseline, then you are just seeing the default provided by the browser.

Here is a working v4 example (v5 example further down):

import React from "react";
import ReactDOM from "react-dom";
import CssBaseline from "@material-ui/core/CssBaseline";
import { MuiThemeProvider, createMuiTheme } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";

const themeLight = createMuiTheme({
  palette: {
    background: {
      default: "#e4f0e2"
    }
  }
});

const themeDark = createMuiTheme({
  palette: {
    background: {
      default: "#222222"
    },
    text: {
      primary: "#ffffff"
    }
  }
});

const App = () => {
  const [light, setLight] = React.useState(true);
  return (
    <MuiThemeProvider theme={light ? themeLight : themeDark}>
      <CssBaseline />
      <Button onClick={() => setLight(prev => !prev)}>Toggle Theme</Button>
    </MuiThemeProvider>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Edit theme body background


Below is a Material-UI v5 example. The only difference from v4 is the name change for ThemeProvider (though this name is also available in v4 in addition to MuiThemeProvider) and createTheme (instead of createMuiTheme).

import React from "react";
import ReactDOM from "react-dom";
import CssBaseline from "@material-ui/core/CssBaseline";
import { ThemeProvider, createTheme } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";

const themeLight = createTheme({
  palette: {
    background: {
      default: "#e4f0e2"
    }
  }
});

const themeDark = createTheme({
  palette: {
    background: {
      default: "#222222"
    },
    text: {
      primary: "#ffffff"
    }
  }
});

const App = () => {
  const [light, setLight] = React.useState(true);
  return (
    <ThemeProvider theme={light ? themeLight : themeDark}>
      <CssBaseline />
      <Button onClick={() => setLight((prev) => !prev)}>Toggle Theme</Button>
    </ThemeProvider>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Edit theme body background

1
votes

ReactDOM doesn't replace the targeted element. I haven't worked with material ui personally. However, if you put the background color you want into your App state as something like 'currentRootColor', then in your App component's render function you could put:

render() {
    document.body.style.backgroundColor = this.state.currentRootColor;

    ...the rest of your App render code
}

This would set the body's background color and if you change 'this.state.currentRootColor', then your App component would re-render with the new background color.

However if you dont already have a < body > tag in your document you would need to add one.

1
votes
import { createMuiTheme } from '@material-ui/core/styles';

const themeX = createMuiTheme({
   palette: {
     type: "dark",
   }
 });

just as simple that, changing the pallets type to dark by default its set to light. This will also help in custom color for other components like typography, icon etc

1
votes

My use case, I only wanted to change background-color of body from within a React component, not the entire theme. Used a global override.

TL;DR code:

// other imports ...
import { makeStyles } from "@material-ui/core/styles";

const useStyles = makeStyles((theme) => ({
  '@global':{
      body:{
        backgroundColor:"#382E7E"
      }
  },
  otherstyles:{
    //  other styles ....
  },

}));


// React component, etc ...