I'm not sure if this is possible or not, after looking at Material UI's documentation on How to Customize, but I'm trying to isolate styleOverrides for a given component using styled() rather than applying a lot of overrides within a global theme file.
Currently, my theme file looks something like this, with some typography and palette overriding Material UI's default theme:
const theme = createTheme({
palette: { ...
},
typography: { ...
}
});
When I use a Chip component (rendered in Storybook currently) and pass in success, primary, secondary, etc. into the color prop, the corresponding theme colors are applied. However, when I try to override the theme files, using styled(), the colors defined in the theme are still being applied - as opposed to my overrides defined. My component file looks like the following:
import { styled } from '#mui/material/styles';
import MuiChip, { ChipProps } from '#mui/material/Chip';
const Chip = styled(MuiChip)<ChipProps>(({ theme }) => ({
colorPrimary: {
backgroundColor: theme.palette.primary.light
},
colorSecondary: {
backgroundColor: theme.palette.secondary.light
}
}));
export default Chip;
You can create your own custom variant and define your own styles to it
const theme = createTheme ({
components : {
MuiButton : {
variants : [
{ props : { variant : 'YouVarName'},
style: { //..your styles } ,
},},
I am using withStyles HOC to provide classes to a component:
const styles = createStyles({
Appbar: ({ backgroundColor }: BaseHeaderProps) => ({
backgroundColor
}),
// ...moreStyles
});
export default withStyles(styles, { name: 'Component' })(Component);
I also need to be able to override the very same classes/styles in the global theme overrides object:
overrides: {
Component: {
Appbar: {
backgroundColor: 'black',
},
},
// more overrides...
The problem I am facing is that the styles in the overrides object will not apply/override the classes defined in the createStyles. The only way overrides would actually override is if the styles are "prop-independent", something like:
const styles = createStyles({
Appbar: {
backgroundColor: 'some-fixed-color',
),
// ...moreStyles
});
Now, the overrides object will override this class and a black background color will be applied to the Appbar.
What I want is to be able to have this overridable functionality even when using "prop-dependent" styles, as the first one shows.
Maybe this helps: The "prop-dependent" callback that returns the style object NEVER gets called when overrides are used in the Theme. I have tried to log the theme object but it never is called.
In the documentation, another component name for overload: "The MuiAppBar name can be used for providing default props or style overrides at the theme level"
https://v4.mui.com/api/app-bar/#appbar-api
export const CustomTheme = {
overrides: {
MuiAppBar: {
backgroundColor: 'black', // ???
},
// more overrides..
},
};
I would like to create my own theme using createTheme() but I want to start with the default material UI theme and just change a few properties in it.
If I call it like so:
const theme = createTheme({
palette: {
primary: {
main: purple[500],
},
secondary: {
main: green[500],
},
},
});
then I am still missing some properties that are needed for several components, theme.palette.action.focus for instance.
Is there a way to extend the default theme?
You can extend the default theme by styleOverrides for #mui/material components.
Here is how to use it in the currently latest version.
import { createTheme } from "#mui/material/styles";
let theme = createTheme();
theme = createTheme(theme, {
paleete: {
...theme.palette,
action: {
focus: "#e6e6e6",
// other variants
}
},
components: {
MuiTableBody: {
styleOverrides: {
root: {
// overrides here
}
}
}
}
});
export default theme;
Take a look at the demo
I have an application that utilizes box's in place of where divs would typically be placed to stay within the MUI ecosystem. My question is, is it possible to have a global theme override for all box components much like how you can globally override the background color for all cards using theme provider.
You can override the Card styles globally using createTheme() because the Card has a name and a styleOverrides callback when it is styled using the styled() API. However, the Box does not, as you can see from the definition here.
const theme = createTheme({
components: {
// this works
MuiCard: {
styleOverrides: {
//
}
},
// this does not work
MuiBox: {
styleOverrides: {
//
}
}
}
});
If you want to create a base component like the Box that can be styled globally by createTheme, you need to define the following properties in the options when calling styled()
name: so the styled engine can identify your component.
overridesResolver: to let MUI know how to resolve the final styles (by combining with other styles created by custom variant, prop and state of the component).
Below is the minimal example for demonstration:
const theme = createTheme({
components: {
MuiDiv: {
styleOverrides: {
root: {
backgroundColor: "green"
}
}
}
}
});
const Div = styled("div", {
name: "MuiDiv",
overridesResolver: (props, styles) => {
return [styles.root];
}
})();
<Div sx={{ width: 10, height: 10 }} />
Live Demo
References
https://mui.com/system/styled/#api
https://mui.com/system/styled/#custom-components
I'm currently customizing a few components using global theme overrides in the hopes of maintaining as much of the integrity of the Material-UI theming engine as possible. I know I could accomplish what I'm trying to do using composition, but I want to see if it's possible to achieve this via overrides.
The Goal
Change the background color of the BottomNavigation component to use the primary color of the current theme, and ensure the label gets a color that is legible on top of that background color.
My Current Approach
const theme = createMuiTheme({
palette: {
primary: {
main: 'rgba(217,102,102,1)'
}
},
overrides: {
MuiBottomNavigation: {
root: {
backgroundColor: 'rgba(217,102,102,1)'
}
},
MuiBottomNavigationAction: {
wrapper: {
color: '#fff'
}
}
}
});
This code accomplishes the task and turns the bottom navigation red and the label/icons white. However, I want the flexibility of being able to change the primary color in the palette and have the component update accordingly.
What I'm Trying To Do
const theme = createMuiTheme({
palette: {
primary: {
main: 'rgba(217,102,102,1)'
}
},
overrides: {
MuiBottomNavigation: {
root: {
backgroundColor: 'primary.main'
}
},
MuiBottomNavigationAction: {
wrapper: {
color: 'primary.contrastText'
}
}
}
});
In this way I could easily update the primary color and not have to worry about changing every reference to it across my overrides. I realize I could extract the rgba value out into a const and that would accomplish part of my goal, but I don't see how I could access something as useful as contrastText in case I choose a much lighter primary color.
So - does anyone know of a way to reference theme palette colors in a theme override definition? Any help would be greatly appreciated!
There's another approach here. createMuiTheme accepts any number of additional theme objects to be merged together.
With that in mind you could replicate your accepted answer without having two different ThemeProvider. And if you move the theme definition to its own module, it won't be recreated on each render.
import { createMuiTheme } from "#material-ui/core/styles";
const globalTheme = createMuiTheme({
palette: {
primary: {
main: "rgba(217,255,102,1)"
}
}
});
const theme = createMuiTheme(
{
overrides: {
MuiButton: {
root: {
backgroundColor: globalTheme.palette.primary.main
},
label: {
color: globalTheme.palette.primary.contrastText
}
}
}
},
globalTheme
);
export default theme;
I updated the CodeSandBox to reflect this.
Ill provide two solutions- one is more readable and maintainable, and one has better performance.
The readable and maintainable approach:
Create nested themes.
One theme will be for defining the palette, and one theme will be for overrides.
Because its two themes, you can access the palette theme from overrides theme:
const globalTheme = createMuiTheme({
palette: {
primary: {
main: 'rgba(217,255,102,1)'
}
},
});
const overridesTheme = createMuiTheme({
overrides: {
MuiButton: {
root: {
backgroundColor: globalTheme.palette.primary.main,
},
label: {
color:globalTheme.palette.primary.contrastText,
}
},
}
})
You can refer to this CodeSandbox
This approach doesn't have good performance, bacause every render a new CSS object will be computed and injected
The better performance approach:
First you create an Mui theme skeleton, with the palette.
After it has been created, you add the styles that rely on the palette (notice how I have to use the spread operator a lot to avoid deleting styles):
const theme = createMuiTheme({
palette: {
primary: {
main: 'rgba(217,255,102,1)'
}
},
})
theme.overrides = {
...theme.overrides,
MuiButton: {
...theme.MuiButton,
root: {
...theme.root,
backgroundColor: theme.palette.primary.main,
},
label: {
...theme.label,
color:theme.palette.primary.contrastText,
}
},
}
You can refer to this CodeSandbox
There's a new way to do it in MUI v5 that is much more straightforward. Suppose you want to override the background color of an Mui Button. Inside the custom theme object, you specify this:
const customTheme = createTheme({
components: {
MuiButton: {
styleOverrides: {
root: {
backgroundColor: 'red',
},
},
},
},
});
This is the usual case for hard coding a value. Now, if you wanted to use some property like the primary color from the custom theme you just made, you can pass an arrow function to the root(or whatever component you need to override) with an object as the argument, and return an object containing the styles you need. You can access the theme inside the returned object.
const customTheme = createTheme({
palette: {
primary: {
main: '#002255',
},
},
components: {
MuiButton: {
styleOverrides: {
root: ({ theme }) => ({
backgroundColor: theme.palette.primary.main,
}),
},
},
});
As you can see, inside the object you can destructure the theme. Similarly you can destructure ownerState, which contains all the props and state of the component, which you can access using dot operator.
To illustrate, I have declared a prop called dark on an Mui Button Component
<Button dark={true}>Random Button</Button>
Now I can access this prop in the button, using the object destructuring
const customTheme = createTheme({
palette: {
primary: {
main: '#002255',
},
},
components: {
MuiButton: {
styleOverrides: {
root: ({ ownerState, theme }) => ({
backgroundColor: ownerState.dark
? theme.palette.primary.dark
: theme.palette.primary.light,
}),
},
},
});
For people looking at this for answers on theming and switching between themes.
https://codesandbox.io/s/material-theme-switching-with-pallete-colors-vfdhn
Create two Theme objects and switch between them. Use the same theme property between them so all your overrides can use the same palette to ensure things are not repeated and we use the overrides completely.
import { createMuiTheme } from "#material-ui/core/styles";
let globalTheme = createMuiTheme({
palette: {
primary: {
main: "#fa4616"
}
}
});
export const LightTheme = createMuiTheme(
{
overrides: {
MuiButton: {
root: {
backgroundColor: globalTheme.palette.primary.main
},
label: {
color: globalTheme.palette.primary.contrastText
}
}
}
},
globalTheme
);
globalTheme = createMuiTheme({
palette: {
primary: {
main: "#0067df"
}
}
});
export const DarkTheme = createMuiTheme(
{
overrides: {
MuiButton: {
root: {
backgroundColor: globalTheme.palette.primary.main
},
label: {
color: globalTheme.palette.primary.contrastText
}
}
}
},
globalTheme
);