Extending the default Material UI theme - reactjs

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

Related

How to pass an object with overrides styles to createTheme

In the project I use MaterialUI for styling components. Now I'm creating a project theme. I need to define overrides object to create theme. I have an overrides object in which I override the colorPrimary for the AppBar. I need to use overrides object to create theme. How can i do this?
// TODO: define overrides object to create theme
const overrides = {
MuiAppBar: {
colorPrimary: {
backgroundColor: "#662E9B",
},
},
};
const theme = createTheme({});
// TODO: use overrides object to create theme
// const theme =;
export {
overrides
};
export default theme;
There are two scenarios that I will give you as an answer here, because I am not sure what exactly is your need.
Scenario A: You want to style all your objects with a new primary color. Not only MuiAppBar, but propagate this to everything else such as buttons, checkboxes... for that, you should go like this:
export const theme = createTheme({
palette: {
primary: { main: "#662E9B" }
},
}
Where as "#662E9B" is your custom primary color. MaterialUI will take care of generating your palette based on your the hex color you provided.
Scenario B: You want your colors to remain the same, but changing only the MuiAppBar backgroundColor
const overrides = {
MuiAppBar: {
styleOverrides: {
root: {
backgroundColor: "#662E9B"
}
}
}
export const theme = createTheme({
components: { ...overrides }
}
Now, for Scenario B, in case const overrides is not being used anywhere else in your code, I would suggest you to just do it like so:
export const theme = createTheme({
components: {
MuiAppBar: {
styleOverrides: {
root: {
backgroundColor: "#662E9B"
}
}
}
}
}
Meaning that there would be no need for doing things separatly.

How can i get the context of the MUI theme?

This is how you create a theme and propagate it using MUI.
import { ThemeProvider } from "#mui/material";
const myTheme = createTheme({
backgroundColor: {
primary: "#f9f9fb",
secondary: "#ededf3",
tertiary: "#cbcbdc",
},
})
const Index: FC = () => {
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
};
Now, for some reason, I need to get the context of the MUI theme in my app.
I've search everywhere but it seems that they do not expose the context anywhere. I found 3 contexts in private-theming, styled-engine and styled-engine-sc but none of them worked.
How can I do that ?
The way you create the theme it wrong should be like following:
const theme = createTheme({
palette: {
primary: {
main: red[500],
},
},
});
with the property palette.
and the way to get values you could use the hook useTheme .
first import
import { useTheme } from "#mui/material";
and inside your components you can use the palette you set to your theme like:
const { palette } = useTheme();
MUI uses the context provided by the styled engine:
import { ThemeContext } from '#mui/styled-engine';
It can also be imported directly from your engine of choice (emotion in the example below):
import { ThemeContext } from '#emotion/react';

Applying Material UI styleOverrides at the component-level with styled()

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 } ,
},},

How can I set a primary color in Chakra UI theme?

I want to set the primary and secondary color in my theme.js/theme.ts. Is there any way to do that?
I am used to work with Material UI components in my React projects.
It is possible to set a palette with 'primary' and 'secondary' there.
I mean something like this:
export const theme = createTheme({
palette: {
primary: {
main: "#7bb9e8"
},
secondary: {
main: "#eb7f7f"
}
}
})
According to this section: https://chakra-ui.com/docs/styled-system/theming/customize-theme#using-theme-extensions
You don't have to pass color='primary' everywhere.
Just create custom theme and then set primary as default color.
This example shows how to set Cyan as default color for every component.
const theme = extendTheme(
{
colors: {
primary: baseTheme.colors.cyan
},
breakpoints,
},
withDefaultColorScheme({
colorScheme: 'primary'
}),
);
As soon as you have defined all color's shades, you can use your custom color as a component's colorSheme:
const theme = extendTheme({
colors: {
primary: {
main: "#7bb9e8",
50: "#e3f2fd",
100: "#bbdefb",
200: "#90caf9",
300: "#64b5f6",
400: "#42a5f5",
500: "#2196f3",
600: "#1e88e5",
700: "#1976d2",
800: "#1565c0",
900: "#0d47a1"
}
}
});
And your component :
<Button colorScheme="primary">Button</Button>
Demo
You can customize the theme in any possible way :
import { extendTheme } from "#chakra-ui/react";
const theme = extendTheme({
colors: {
primary: {
main: "#7bb9e8"
},
secondary: {
main: "#eb7f7f"
}
}
});
Then pass this theme to ChakraProvider
//index.js
<ChakraProvider theme={theme}>
<App />
</ChakraProvider>
And you will be able to use your own colors accessing the theme via useTheme hook:
import { useTheme } from "#chakra-ui/react";
...
const theme = useTheme();
...
<Button bg={theme.colors.primary.main}>Button</Button>
or override a component styles globally inside the component object
Demo
You can set two variants of primary colors with default and _dark property. It will be used depending on actual color mode (light/dark theme).
import { extendTheme } from '#chakra-ui/react'
const theme = extendTheme({
initialColorMode: 'light',
semanticTokens: {
colors: {
text: {
default: '#16161D',
_dark: '#ade3b8',
},
primary: {
default: '#FF0080',
_dark: '#fbec8f',
},
})
export default theme

Material-UI Theme Overrides Leveraging Theme Palette Colors

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
);

Resources