'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
Solution 1:[1]
Here's the relevant portion of the documentation:
The code that handles theme nesting can be found here:
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.
Solution 2:[2]
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>;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Ryan Cogswell |
Solution 2 |