Material UI: Use theme in React Class Component

Viewed 12193

I am looking for something like ThemeConsumer (which probably doesn't exist). I've React component and I am using withStyles() higher-order component to inject custom styles. It's pretty well described in documentation but I didn't find any example which uses theme.


I have some base component which contains ThemeProvider. It means any of MUI components are being affected by it.

const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const theme = getTheme(prefersDarkMode);
return (
   <ThemeProvider theme={theme}>
      ...
   </ThemeProvider>
)

I also use some functional components with makeStyles() to create styles with provided theme.

const useStyles = makeStyles(theme => ({
   // here I can use theme provided by ThemeProvider
});

But it can't be used in class components. So I am using withStyles() HOC.

const styles = {
   // I would like to use here provided theme too
}
export default withStyles(styles)(SomeComponent);

Summary of my question:
How do I use provided theme in class component?

4 Answers

withStyles supports similar syntax as makeStyles:

const styles = theme => ({
   // here I can use theme provided by ThemeProvider
});
export default withStyles(styles)(SomeComponent);

Here's a simple working example:

import React from "react";
import { withStyles } from "@material-ui/core/styles";
import Paper from "@material-ui/core/Paper";

const StyledPaper = withStyles(theme => ({
  root: {
    backgroundColor: theme.palette.secondary.main
  }
}))(Paper);
export default function App() {
  return (
    <StyledPaper className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </StyledPaper>
  );
}

Edit withStyles using theme

A component decorated with withStyles(styles) gets a special classes prop injected, which may be used for your custom styles. For example:

import { Box } from "@material-ui/core"
import { withStyles } from "@material-ui/core/styles"

const styles = theme => ({
  myCustomClass: {
    color: theme.palette.tertiary.dark
  }
})

class myComponent extends Component {
  render() {
    const { classes, theme } = this.props
    // In last line, you see we have passed `{ withTheme: true }` option
    // to have access to the theme variable inside the class body. See it
    // in action in next line.

    return <Box className={classes.myCustomClass} padding={theme.spacing(4)} />
  }
}

export default withStyles(styles, { withTheme: true })(myComponent)

If you pass { withTheme: true } option to withStyles HOC, you'll get the theme variable injected as a prop also.

If you have other HOCs (e.g. Redux's connect, Router, etc) applied to your component, you may use it like this:

export default withStyles(styles, { withTheme: true })(
   withRouter(connect(mapStateToProps)(myComponent))
)

A more comprehensive explanation for this topic could be found in this article: Using Material UI theme variable in React Function and Class Components.

Use withTheme HOC

modified example from docs

import { withTheme } from '@material-ui/core/styles';

class DeepChildRaw 
{
 /*...*/
  render()
  {
    return <span>{`spacing ${this.props.theme.spacing}`}</span>;
  }
}

const DeepChild = withTheme(DeepChildRaw);

if are working with Class Components, you can use like here ;)

import React from 'react';
import Routes from './Routes';
import '../custom.css';
import { BrowserRouter } from 'react-router-dom';
import { MuiThemeProvider, createTheme } from '@material-ui/core/styles';

const theme = createTheme({
  palette: {
    primary: {
      main: '#fff'
    },
    secondary: {
      main: '#351436'
    }
  }
});

class App extends React.Component {
  render() {
    return (
      <div className="App">
        <MuiThemeProvider theme={theme}>
          <BrowserRouter>
            <Routes />
          </BrowserRouter>
        </MuiThemeProvider>
      </div>
    )
  }
}

export default App;
Related