20

By default the MUI theme is a combination of several pre-defined objects such as typography: {...}, palette: {...} etc.

Is is possible to add a custom object into this setup and still use createTheme?

So for example the theme object would become:

const theme = {
  palette: {
    primary: '#000'
  },
  typography: {
    body1: {
      fontFamily: 'Comic Sans'
    }
  },
  custom: {
    myOwnComponent: {
      margin: '10px 10px'
    }
  }
}
NearHuscarl
  • 66,950
  • 18
  • 261
  • 230
Remi
  • 4,663
  • 11
  • 49
  • 84

4 Answers4

23

Yes, this works just fine. Material-UI does a deep merge of its defaults with the object you provide with some special handling for keys that get merged in a more sophisticated fashion (such as palette, typography and a few others). Any unrecognized keys will come through unchanged.

Below is a working example:

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

import {
  useTheme,
  createMuiTheme,
  MuiThemeProvider
} from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
const theme = createMuiTheme({
  palette: {
    primary: {
      main: "#00F"
    }
  },
  typography: {
    body1: {
      fontFamily: "Comic Sans"
    }
  },
  custom: {
    myOwnComponent: {
      margin: "10px 10px",
      backgroundColor: "lightgreen"
    }
  }
});
const MyOwnComponent = () => {
  const theme = useTheme();
  return (
    <div style={theme.custom.myOwnComponent}>
      Here is my own component using a custom portion of the theme.
    </div>
  );
};
function App() {
  return (
    <MuiThemeProvider theme={theme}>
      <div className="App">
        <Button variant="contained" color="primary">
          <Typography variant="body1">
            Button using main theme color and font-family
          </Typography>
        </Button>
        <MyOwnComponent />
      </div>
    </MuiThemeProvider>
  );
}

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

Edit custom properties in theme

Ryan Cogswell
  • 75,046
  • 9
  • 218
  • 198
  • 4
    I believe the ability to do this has been deleted. I'm trying to do it in my code using Typescript and I'm getting an error that `custom` is not included in `ThemeOptions`. This may be just a typescript issue but wanted to share in case anyone else comes across this. – CWSites Jan 13 '21 at 18:57
  • 4
    @CWSites not sure if you cared, but I got a typescript solution working. In my `theme.ts` file, if you ```declare module '@material-ui/core/styles/createMuiTheme' { interface Theme { customthing: string; } interface ThemeOptions { customthing?: string; } }``` then you can ```const theme = createMuiTheme({ customthing: 'red', ...otherOverRides })``` – Syed Jafri Jan 20 '21 at 03:47
  • 3
    what about typescirpt? – Sarmad Shah Feb 23 '21 at 15:22
  • Here's the documentation for how to do this in typescript: https://material-ui.com/guides/typescript/#customization-of-theme – MikeyLikesIt Jul 21 '21 at 16:28
14

You can add custom variables in your MUI theme as easy as:

const theme = createTheme({
  myField: {
    myNestedField: 'myValue',
  },
});

But if you're using Typescript, you also need to update the definition of ThemeOptions and Theme using module augmentation:

declare module '@mui/material/styles' {
  // fix the type error when referencing the Theme object in your styled component
  interface Theme {
    myField?: {
      myNestedField?: string;
    };
  }
  // fix the type error when calling `createTheme()` with a custom theme option
  interface ThemeOptions {
    myField?: {
      myNestedField?: string;
    };
  }
}

If you want to reuse the type between Theme and ThemeOptions, you can define a common interface and inherit it in both places:

declare module '@mui/material/styles' {
  interface CustomTheme {
    myField?: {
      myNestedField?: string;
    };
  }

  interface Theme extends CustomTheme {}
  interface ThemeOptions extends CustomTheme {}
}

Also note that you don't have to create custom variables in MUI theme if you want to override a custom component using createTheme(). See this answer for more detail.

Live Demo

Codesandbox Demo

NearHuscarl
  • 66,950
  • 18
  • 261
  • 230
  • 1
    Make sure to add `declare module @mui/material/styles { ... }` in the file where you are creating the theme (invoking the function `createTheme()`) – keemor Feb 11 '22 at 12:40
  • Can I somehow make the module augmentation global? I've tried putting this into a theme.d.ts file but the type inference doesn't carry over. For my case I want to use the Theme in a lot of places so starting each file with the augmentation is not an option – Zwei Euro Jan 10 '23 at 11:29
0

On top of the answers above, if you are using sx for styling you can access the custom theme like so:

<div sx={{ margin: (theme) => theme.custom.myOwnComponent.margin }} />
Gilad Dahan
  • 508
  • 5
  • 19
0

I use this case with typescript without any declarations:

const theme: Theme = createTheme({ 
  palette: {...},
  components: {...},
  ...
}, {
  customValues: {
    customKey: customValue,
  }
});

Then I can use it in my code so:

const theme = useTheme();
const myCustomValueFromTheme = theme.customValues.customKey;

Or you can use it in your styles for example like this:

const StyledContainer: StyledComponent<any, any> = styled.div`
  background-color: ${props => props.theme.customValues.customKey};
`;
fqf
  • 71
  • 1
  • 4