ZChu
ZChu

Reputation: 45

Global theme with TypeScript/React/Material-UI

I'm following the official tutorial to create global theme for my app.

My root component is supposed to provide global theme:

const themeInstance = {
  backgroundColor: 'cadetblue'
}

render (
    <ThemeProvider theme={themeInstance}>
      <ChildComponent />
    </ThemeProvider>,
    rootNode
) 

But I can't seem to get my child component to apply the theme:

const useStyles = makeStyles(theme => {
  childComp: {
    backgroundColor: theme.backgroundColor
  }
})

const ChildComponent: FC = () => {
  const classes = useStyles()
  return (
    <div className={classes.childComp}>I'm a div</div>
  )
}

<ChildComponent /> is getting rendered un-styled.

It looks to be a types mismatch issue of some sort as when I started to play around with types of theme parameter, the browser has rendered the expected output (<ChildComponent /> div with background-color: cadetblue) for split second than failed with error.

Any help to figure out where did I go wrong way are quite appreciated.

Live sandbox can be found over here.


Upvotes: 1

Views: 2684

Answers (2)

NearHuscarl
NearHuscarl

Reputation: 81290

You need to type your custom theme. By default makeStyle will use default theme type which has the following signature:

export interface Theme {
  shape: Shape;
  breakpoints: Breakpoints;
  direction: Direction;
  mixins: Mixins;
  components?: Components;
  palette: Palette;
  shadows: Shadows;
  spacing: Spacing;
  transitions: Transitions;
  typography: Typography;
  zIndex: ZIndex;
  unstable_strictMode?: boolean;
}

As you can see, it doesn't have backgroundColor property. You need to update the Theme definition by using module augmentation to make typescript stop complaining about the incorrect theme type.

import { Theme } from "@material-ui/core/styles/createMuiTheme";
import { createMuiTheme } from "@material-ui/core/styles";

declare module "@material-ui/styles" {
  interface DefaultTheme extends MyTheme {}
}

declare module "@material-ui/core/styles/createMuiTheme" {
  interface ThemeOptions extends MyTheme {}
}

export interface MyTheme extends Theme {
  backgroundColor: string;
}

const theme = createMuiTheme({
  backgroundColor: "red"
});

export { theme };

In your component

const useStyles = makeStyles((theme) => ({
  childComp: {
    backgroundColor: theme.backgroundColor
  }
}));

Live Demo

Edit 64294250/global-theme-with-typescript-react-material-ui

Upvotes: 1

SILENT
SILENT

Reputation: 4258

This happens to me often. Try the following:

const useStyles = makeStyles(theme => ({
  childComp: {
    backgroundColor: theme.backgroundColor
  }
}));

Note the ( )

Live sandbox: https://stackblitz.com/edit/react-ts-e7vw8s?file=childComponent.tsx

Upvotes: 1

Related Questions