Material UI doesn't use overridden styles when using useTheme hook - reactjs

I'm trying to use custom theming in Material UI like so:
const theme = createMuiTheme({
palette: {
primary: {
main: PRIMARY_COLOR, // "#121212"
},
secondary: {
main: SECONDARY_COLOR, // "#F7D600"
},
},
});
const Wrapper = ({ children }) => {
return (
<ThemeProvider theme={theme}>{children}</ThemeProvider>
);
};
This works for things like buttons:
<Button
variant="contained"
color="secondary"
/>
In this case, the hex color #F7D600 gets applied.
But when I try to use the same color on my components using makeStyles, it doesn't seem to recognize it. It just uses the default by Material UI:
const useStyles = makeStyles((theme) => ({
someElement: {
backgroundColor: theme.palette.primary.main // <- not working. it uses the default purple color
}
});
I also tried useTheme but it's the same result:
const SomeComponent = () => {
const theme = useTheme();
return (
<Box style={{ backgroundColor: theme.palette.primary.main }}></Box>
);
}
Any ideas what I could be missing?

I can't see your import statement, but I use MuiThemeProvider. That could be your issue. Everything else looks right to me
import { MuiThemeProvider } from '#material-ui/core';

Use the below style to override any component in material-UI
import { createMuiTheme, colors } from '#material-ui/core'
const theme = createMuiTheme({
palette: {
background: {
dark: '#F4F6F8',
default: colors.common.white,
paper: colors.common.white,
},
primary: {
main: colors.indigo[500],
},
secondary: {
main: colors.indigo[500],
},
text: {
primary: colors.blueGrey[900],
secondary: colors.blueGrey[600],
},
common: {
tableHeader: '#DEF3FA',
},
action: {
oddRowColor: '#def3fa2e',
},
},
zIndex: {
modal: 10010, // override modal zIndex
appBar: 1000, // override Appbar
},
overrides: { 'MTableHeader-header': { root: { width: '143px !important' } } },
})
// use in your component
const StyledTableRow = withStyles((theme) => ({
root: {
'&:nth-of-type(odd)': {
backgroundColor: theme.palette.action.oddRowColor,//defined in theme
},
padding: 'dense',
},
}))(TableRow)
[https://material-ui.com/customization/default-theme/][1]

Related

Using the theme context "Material UI 5" React

I Try To Change the default Theme In Material UI By Using createTheme:
I Follow Material UI Dec. (Using Typescript):
import { makeStyles } from '#mui/styles';
import { createTheme, ThemeProvider } from '#mui/material/styles';
const theme = createTheme({
palette: {
primary: {
light: '#d2d8de',
main: '#00a1a6',
dark: '#5c6b77',
contrastText: '#313944',
},
},
typography: {
fontSize: 12
},
});
const useStyles = makeStyles((theme) => ({
root: {
color: theme.palette.primary.main,
}
}));
const App = (props) => {
const classes = useStyles();
return <ThemeProvider theme={theme}><div {...props} className={classes.root}></ThemeProvider>;
}
Typography It's Work As Default But If I use theme is an empty object;
It's Show Error:
TypeError: Cannot read properties of undefined (reading 'primary')
Note: your theme provider will pass theme to your wrapped child components only. So if you are calling theme outside theme provider it will not be accessible.
So you need to wrap styling inside child component
Also pass options for your new theme, its empty.
You need to pass somehting like this, example :
const theme = createTheme({
palette: {
primary: {
main: purple[500],
},
secondary: {
main: green[500],
},
},
});
return (
<ThemeProvider theme={theme}>
<ChildComponent />
</ThemeProvider>
);
ChildComponent
const useStyles = makeStyles(theme => ({
...theme
}));
const ChildComponent = () => {
const classes = useStyles();
return //some dom elements using classes
}
Please check - https://mui.com/customization/theming/#createtheme-options-args-theme

React / Material-UI: Use variable reference in custom theme

Is there a way in Material-UI (React) to use a reference in a custom theme to a variable defined in the same theme? For example, the component MuiBottomNavigation should use the primary color (main) as background.
import { createTheme, useTheme } from '#mui/material/styles';
const theme = createTheme({
palette: {
primary: {
main: '#f6b1b2'
}
},
components: {
MuiBottomNavigation: {
styleOverrides: {
root: {
// This is not working
backgroundColor: {palette.primary.main}
},
}
}
}
});
You can achieve this by creating several themes and then merging them into one:
// Define all your default styles
const themeBase = createTheme({
palette: {
primary: {
main: "#f6b1b2"
}
}
});
// Define all your component styles
const themeComponents = createTheme({
components: {
MuiBottomNavigation: {
styleOverrides: {
root: {
backgroundColor: themeBase.palette.primary.main
},
}
}
}
});
const theme = createTheme({
...themeBase,
components: themeComponents.components,
});
Of course, you wouldn't need to create an extra theme for the components. You could also just insert them into the final theme.
No, you can't. there is no such API to access the theme when you define it. So something like this wouldn't work
styleOverrides: {
root: {
backgroundColor: theme => theme.palette.primary.main
},
}
To workaround this you can put the commonly shared value into a variable and reference it:
const primaryMain = '#f6b1b2';
const theme = createTheme({
palette: {
primary: {
main: primaryMain,
}
},
components: {
MuiBottomNavigation: {
styleOverrides: {
root: {
backgroundColor: primaryMain,
}
}
}
}
});
If you only need to access a default theme variable, you can create one and reference it like this:
const defaultTheme = createTheme();
const theme = createTheme({
components: {
MuiBottomNavigation: {
styleOverrides: {
root: {
backgroundColor: defaultTheme.palette.primary.main,
}
}
}
}
});

How to use 'overrides' theme when using seed prefix with createGenerateClassName in Material ui

We are extending material ui theme, but when doing :
const theme = createMuiTheme({
overrides: { MuiOutlinedInput: { root: { backgroundColor: 'red' } } },
})
the changes dont apply. We are also using createGenerateClassName:
const generateClassName = createGenerateClassName({
productionPrefix: 'c',
seed: 'corp',
})
So, when taking a look at the html code, I noticed the class MuiOutlinedInput is now corp-MuiOutlinedInput-root, so we decided to use the following override instead:
const theme = createMuiTheme({
overrides: { "corp-MuiOutlinedInput": { root: { backgroundColor: 'red' } } },
})
But it does not work either. Any clue?

Theme nesting with Material UI

I have many datatables throughout my website and for the most part they are all styled the same. There are several different styles I need to apply to some of them. I want to create a global theme for handling everything across the site including the basic datatable styles and I also want to have a local theme to tweak the individual datatables a little.
Here is what I've got.
https://codesandbox.io/embed/jolly-antonelli-fg1y1
This is structure like this
<Test>
<PrimaryThemeHere> //All have Border 1px red
<TestChild>
<SecondaryThemeHere> //blue background
<Datatable />
</SecondaryThemeHere>
</TestChild>
<TestChild2>
<SecondaryThemeHere> //Red background
<Datatable />
</SecondaryThemeHere>
<TestChild2>
</PrimaryThemeHere>
</Test>
The primary theme looks like this:
const theme = createMuiTheme({
overrides: {
MuiTableBody: {
root: {
border: "1px solid red"
}
},
MuiTableCell: {
root: {
border: "1px solid red"
}
}
}
});
and the nested theme looks like this:
getMuiTheme = () =>
createMuiTheme({
overrides: {
MuiTableRow: {
root: {
backgroundColor: "blue"
}
}
}
});
I can never get the border red to show alongside the background color. It always chooses one or the other. How can I get a combination of the initial primary theming (border 1px red) and the background color or blue and red.
Please help
Here's the relevant portion of the documentation:
https://material-ui.com/customization/themes/#nesting-the-theme
The code that handles theme nesting can be found here:
https://github.com/mui/material-ui/blob/master/packages/mui-system/src/ThemeProvider/ThemeProvider.js
Here is the current code:
// To support composition of theme.
function mergeOuterLocalTheme(outerTheme, localTheme) {
if (typeof localTheme === 'function') {
const mergedTheme = localTheme(outerTheme);
warning(
mergedTheme,
[
'Material-UI: you should return an object from your theme function, i.e.',
'<ThemeProvider theme={() => ({})} />',
].join('\n'),
);
return mergedTheme;
}
return { ...outerTheme, ...localTheme };
}
Notice that the final line (return { ...outerTheme, ...localTheme };) is doing a shallow merge of the two themes. Since both of your themes have the overrides property specified, the localTheme overrides will completely replace the outerTheme overrides.
However, you can do a more sophisticated merge of the two themes, by providing a function to the ThemeProvider. For instance TestChild can look like this:
import React, { Component } from "react";
import { MuiThemeProvider } from "#material-ui/core/styles";
import MUIDataTable from "mui-datatables";
const localTheme = {
overrides: {
MuiTableRow: {
root: {
backgroundColor: "blue"
}
}
}
};
const themeMerge = outerTheme => {
// Shallow copy of outerTheme
const newTheme = { ...outerTheme };
if (!newTheme.overrides) {
newTheme.overrides = localTheme.overrides;
} else {
// Merge the overrides. If you have the same overrides key
// in both (e.g. MuiTableRow), then this would need to be
// more sophisticated and you would probably want to use
// a deepMerge function from some other package to handle this step.
newTheme.overrides = { ...newTheme.overrides, ...localTheme.overrides };
}
return newTheme;
};
class TestChild extends Component {
render() {
const columns = [
{
name: "Message"
},
{
name: "Date"
},
{
name: "Dismiss"
}
];
const data = [["test", "15/01/19", "", ""], ["test", "15/01/19", "", ""]];
let options = {
filterType: "dropdown",
responsive: "stacked",
print: false,
search: false,
download: false,
selectableRows: "none"
};
return (
<div>
<MuiThemeProvider theme={themeMerge}>
<MUIDataTable
title={"Test"}
data={data}
columns={columns}
options={options}
/>
</MuiThemeProvider>
</div>
);
}
}
export default TestChild;
In my version of your sandbox, I only fixed TestChild2.js.
For me the whole inner theme worked, except the mode. I could fix it by adding a <Paper /> component.
import { createTheme, Paper, ThemeProvider } from "#mui/material";
const outerThemeOptions = {
palette: { mode: "light" },
typography: { body1: { fontSize: 14 } },
};
const innerThemeOptions = {
palette: { mode: "dark" },
};
const outerTheme = createTheme(outerThemeOptions);
const innerTheme = createTheme({
...outerThemeOptions,
...innerThemeOptions,
});
<ThemeProvider theme={outerTheme}>
<Child1 />
<ThemeProvider theme={innerTheme}>
<Paper elevation={0}>
<Child2 />
</Paper>
</ThemeProvider>
</ThemeProvider>;

Alternative to innerTheme when we want to have different primaryTypographyProps

I have a component which has a List customized with ListeItems and Icons and Buttons. I want to use this component in 2 different places. In one place, I set the MuiListItemTextTypography props this way..
const theme = createMuiTheme({
.
.
.
typography: {
useNextVariants: true
body1: {
fontSize: '14px'
}
},
props: {
MuiListItemText: {
primaryTypographyProps: {
variant: "body1"
},
secondaryTypographyProps: {
variant: "body2"
}
}
}
})
But a second component wants the font size to be 12 px, so I did it this way
const innerTheme = createMuiTheme({
typography: {
body1: {
fontSize: '12px'
}
},
props: {
MuiListItemText: {
primaryTypographyProps: {
variant: "body1"
},
secondaryTypographyProps: {
variant: "body1"
}
}
}
});
and wrapped the second component in new Theme
<MuiThemeProvider theme={innerTheme}>
<ListItems itemsList={secondItem}/>
</MuiThemeProvider>
It works fine, but the drawback is that I lose all the styles set in main theme when I wrap it in an inner theme
How can I do this so that I do not lose all that in the first theme.
There is a good example of how to do this here: Nesting the Theme
MuiThemeProvider accepts a function, so you can redefine innerTheme as:
const innerTheme = {
typography: {
body1: {
fontSize: '12px'
}
},
props: {
MuiListItemText: {
primaryTypographyProps: {
variant: "body1"
},
secondaryTypographyProps: {
variant: "body1"
}
}
}
}
And then change your markup to:
<MuiThemeProvider theme={theme => createMuiTheme({...theme, ...innerTheme})}>
<ListItems itemsList={secondItem}/>
</MuiThemeProvider>

Resources