Set MUI Theme for Specific React Page - reactjs

We are using MUI with our React site and currently have light & dark themes. I would like to force the light theme on a specific page (log in). For some reason, I cannot seem to find a solution anywhere online. How can I go about doing this?

import { createTheme, ThemeProvider } from '#material-ui/core';
const loginTheme = createTheme({
palette: {
background: {
default: '#303030',
paper: '#424242'
},
},
});
<ThemeProvider theme={loginTheme}>
wrap the content you want to use the above theme
</ThemeProvider>

Related

How can I use useTheme in Material UI 5?

I just started using Material UI 5.0.4 (with styled-components), and I wanted to access the theme in a component. I looked online and saw useTheme, so I checked the docs and found it - #mui/styles/useTheme. However, it was the legacy documentation, and #mui/styles does not exist in MUI 5. So, I looked at #mui/system instead, and found the section "Accessing the theme in a component". However, this just points back to the legacy documentation!
After the docs didn't seem to help me, I decided to use Visual Studio Code's "Quick Fix" feature, where if you hover over the function, VSCode will give you a list of options to import. Here is the list of options I tried, and why they didn't work:
#mui/material/styles/useTheme - Returns the default theme object, no matter what. Looking into the source code, this is literally what it does - it switches to the default theme, and then returns the theme.
#mui/material/private-theming/useTheme - This just returns null. I feel like I shouldn't be accessing this anyway (it says private-), but I tried it anyway.
#mui/system/useTheme - This is what I was hoping would work. However, this is also probably the weirdest one. It gives me the default theme, but it excludes many properties. For example, it only provided palette.mode, and there are no other keys under palette than that. (You can see the whole thing below)
{
"breakpoints": {
"keys": ["xs", "sm", "md", "lg", "xl"],
"values": { "xs": 0, "sm": 600, "md": 900, "lg": 1200, "xl": 1536 },
"unit": "px"
},
"direction": "ltr",
"components": {},
"palette": { "mode": "light" },
"shape": { "borderRadius": 4 }
}
styled-components/useTheme - Returns undefined.
#mui/styled-engine-sc/useTheme - Returns undefined. (I have a feeling this is the same thing as styled-components/useTheme.)
Those were all the suggestions that VSCode could give me, apart from things like #mui/system/useTheme vs #mui/system/useTheme/useTheme (which is the same thing). I also tried googling stuff but it would always be really old, like:
Issue #8958 on GitHub for MUI which references #material-ui/core/styles which is v4 and not in v5
SO question labelled "access the theme from outside material-ui component" which references the legacy docs (#material-ui/styles does not exist anymore, and #mui/material/styles/useTheme does not work as explained above)
Please, if someone knows, how do you get the theme in a component in MUI 5?
It turns out that the correct useTheme is #mui/material/styles/useTheme, and you cannot use useTheme in the same component that you do the ThemeProvider in. For example, this:
const App = () => {
const theme = useTheme();
return (
<ThemeProvider theme={myTheme}>
<Box bgcolor={theme.palette.background.default} width={100} height={100} />
</ThemeProvider>
);
};
Will not work properly. However, this:
const MyComponent = () => {
const theme = useTheme();
return <Box bgcolor={theme.palette.background.default} width={100} height={100} />;
};
const App = () => (
<ThemeProvider theme={myTheme}>
<MyComponent />
</ThemeProvider>
)
Will work properly, as useTheme is used in a separate component.
Just in case anyone wonder why you can't use useTheme in the same component as
ThemeProvider, it is because useTheme has to be in a component wrapped by ThemeProvider. The context isn't available to components outside of that component tree.
For anybody still struggling with this, I got it working by importing createTheme, ThemeProvider and useTheme all directly from #mui/material...
theme.js:
import { createTheme } from '#mui/material';
export const theme = createTheme({
...
});
_app.tsx (I'm using next.js)
import { CssBaseline, ThemeProvider } from '#mui/material';
import type { AppProps } from 'next/app';
import React from 'react';
import { theme } from '../theme';
function MyApp({ Component, pageProps }: AppProps) {
return (
<React.StrictMode>
<CssBaseline />
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
</React.StrictMode>
);
}
export default MyApp;
navigation.tsx (my component with useTheme)
import { Drawer, useTheme } from '#mui/material';
import React from 'react';
const Navigation = (): JSX.Element => {
const theme = useTheme();
const drawerSx = {
'& .MuiDrawer-paper': {
background: `linear-gradient(to bottom right, ${theme.palette.primary.main}, ${theme.palette.primary.dark})`,
},
};
return (
<Drawer sx={drawerSx} variant="permanent">
...
</Drawer>
);
};
export default Navigation;
I was struggling before I did this, it was only applying the default theme, not the custom one.
If you are using the useTheme from #mui/material/styles and is still not working check if you un your AppTheme.jsx (or where you are using the ThemeProvider) check that you are using the ThemeProvider from #mui/material/styles and not the ThemeProvider of #emotion/react. That why in my case (using MUI v5) useTheme wasn't working with my own theme (in particular with my custom breakpoints).
As already answered, your first usage of useTheme must be wrapped inside ThemeProvider in a parent component.
(useTheme needs a theme provider to draw from.)
Technically, you can useTheme in the same component as ThemeProvider, as long as the component is used in a parent component that wraps it with ThemeProvider
Example:
const InnerComponent = () => {
// Use the theme from `App` below
const appTheme = useTheme();
// Local Theme. (May want to wrap with `useMemo` too.)
const innerTheme = createThemeV5(appTheme, {
// Local theme overrides
});
return (
<ThemeProvider theme={innerTheme}>
<Box />
</ThemeProvider>
);
}
const App = () => {
return (
<ThemeProvider theme={myTheme}>
<InnerComponent />
</ThemeProvider>
);
};

How to use react-admin with material ui version 5

How to use react-admin with Material UI version 5. Is it possible to make it independent from material ui 4?
You'll need to use the latest theme and the legacy theme. The legacy theme should be set on the Admin component and the latest theme should be set via the ThemeProvider.
MUI v5 and MUI v4.x aren't that different in terms of the basic default theme. Given some things have been moved around and one or two keys removed. You can create an object to be the global theme (containing the typography, palette, breakpoints, etc if you customize these values).
A key difference in v5.x and v4.x is how style overrides and default props for components are defined. You will need to create a function to loop over all themeV5.components and grab the values in defaultProps and styleOverrides and assign them under the themeV4.props and themeV4.overrides.
import { ThemeProvider } from '#mui/material/styles';
import { createTheme } from '#mui/material/styles';
import { createTheme as createThemeV4 } from '#material-ui/core/styles';
const theme = {
sidebar: {...},
palette: {...},
typography: {...},
}
let latestTheme = createTheme({
...theme,
components: {},
});
let legacyTheme = createThemeV4({
...theme,
overrides: {},
props: {},
});
<ThemeProvider theme={latestTheme}>
<Admin
title={APP_NAME}
authProvider={authProvider}
dataProvider={dataProvider}
i18nProvider={i18nProvider}
history={history}
theme={legacyTheme}
>
{resources}
</Admin>
</ThemeProvider>
Looks like the next major version (4) of React-Admin adds support for MUI v5

Extending Material UI's existing dark mode colors

Material UI's default theme ships a palette of colors, including a special set of dark colors (docs, code).
What makes these dark mode colors special is components who consume them don't need to depend on knowing the theme's palette.mode (aka light/dark mode) - they update automatically.
codesandbox demo
My goal is to extend this set of colors, such that components I write can use new colors beyond this built-in set, e.g. theme.palette.myColor and benefit from the same automatic behavior.
In other words, I don't want to have dark mode logic be duplicated in each theme-consuming component:
const WhatIDontWantComponent = () => (
<Box
sx={{
color: (theme) =>
theme.palette.mode === "light"
? theme.palette.myColor.light
: theme.palette.myColor.dark,
}}
/>
);
I instead want to use
const WhatIWantComponent = () => (
<Box
sx={{
color: (theme) => theme.palette.myColor
}}
/>
);
So myColor would be included in the light/dark set that already exists, and benefit from this automatic behavior.
Possible? Is there some way to accomplish this within my app without patching MUI in some way to accept custom colors?
deps
#material-ui/core version 5.0.0-beta.4
react, react-dom 17.0.2
next.js 11.0
Ended up going with this:
const baseTheme = createTheme({...common options...})
export const lightTheme = createTheme({ ...light specific...}, baseTheme)
export const darkTheme = createTheme({ mode: "dark", ...dark specific...}, baseTheme)
based on this discussion.
We basically perform theme composition in multiple steps + utilizing how the second arg to createTheme() gets deepmerge'd.
Once you have the two themes, you could consider setting up a toggle by bringing your own mode:
<ThemeProvider theme={mode ? lightTheme : darkTheme}>
{...app...}
</ThemeProvider>
This works, but IMO a downside of this approach though is that I have two themes and have to manage dark/light state externally. Not a huge problem but feels a bit redundant -- in my mind dark/light mode seems like a concern that could (should) be handled internally to a single theme.
Perhaps there are good reasons against, but IMO it feels more ergonomic if MUI would allow users to specify our own dark palette, like I asked in my original question, vs the current hard coded one.
So if you're looking for custom MUI dark colors, this approach seems to be the best one given the situation right now.
You can customize the material-ui theme using theme provider component in order to add your custom colors for e.g,
import { createTheme, colors } from '#material-ui/core/styles';
const theme = createTheme({
palette: {
background: {
default: "#F6F7FF",
paper: colors.common.white
},
primary: {
main: "#43A047"
},
secondary: {
main: "#43A047"
},
text: {
primary: "#000000",
secondary: "#6b778c"
},
// Add your custom colors if any
},
});
You can write this configuration code inside a separate file and then import it into your root component file.
import theme from "src/theme";
import { ThemeProvider } from "#material-ui/core";
<ThemeProvider theme={theme}>
<YourRootComponent />
</ThemeProvider>
Then consume it the same way you do it for the default material UI colors
Also, you can customize typography, shadows, override default class, and much more check out this

The optimum way of changing Material UI react theme at runtime

I am new to React and Material UI and still am trying to grasp the composition over inheritance.
I am trying to achieve switching to dark/light theme at runtime in a react app. I have achieved it somehow but with lots of code duplication. I am sure there is a better way.
Here is what I have so far:
Theme.js
import { createMuiTheme } from "#material-ui/core/styles";
export const darkTheme = createMuiTheme({
palette: {
type: "dark",
},
//.....a lot of items
});
export const lightTheme = createMuiTheme({
palette: {
type: "light",
},
//.....duplicating same items as above
});
App.js
import { lightTheme, darkTheme } from "../shared/Theme";
const App = ({
theme
}) => {
return (
<ThemeProvider theme={theme === "dark" ? darkTheme : lightTheme}>
{/*Components...*/}
</ThemeProvider>
);
};
The theme props is getting injected using redux and its doing its job fine. This is workable solution but not the best one.
I found in Material UI documentation that we can have [outer and inner theme provider][1] and I tried doing the following (but it didn't work):
<ThemeProvider theme={…} >
<ThemeProvider theme={outerTheme => ({ darkMode: true, ...outerTheme })}>
{...Component}
</ThemeProvider>
</ThemeProvider>
I am aware of useStyle hook but it just lets you create class names that you can use in your component. What I want is: take a certain section of the existing theme object and replace a property in it.
Any help will is appreciated. Thanks for reading this far!
[1]: https://material-ui.com/styles/advanced/#main-content
"Duplication" is a problem when there is property-value repetition, otherwise is an alternate configuration, that is, repeating objects or their properties are not an issue. If there is no property-value repetition, using separate objects is the way, MUI does it, so you are right on track.
Now, Assuming you meant property-value repetition (shared styling) at:
//.....duplicating same items as above
where there is property-value repetition mixed with alternate configuration within your objects, and based on your goal:
take a certain section of the existing theme object and replace a property in it
Try a factory method:
const createThemeOptions = (isDarkMode)=>({
palette: {
mode: isDarkMode? "dark" : "light", // alternate configuration
},
primary: {
main: indigo['A700'], // property-value repetition(shared styling)
},
secondary: {
main: isDarkMode? deepOrange['A200'] : deepOrange['900'], // alternate configuration
},
// make your other object properties shared or alternate...
});
export const darkTheme = createMuiTheme(createThemeOptions(true));
export const lightTheme = createMuiTheme(createThemeOptions());

How to disable Material-UI contrast ratio console errors?

My console is full of
Material-UI: the contrast ratio of 2.590660811372324:1 for #fff on #5EB44B
falls below the WCAG recommended absolute minimum contrast ratio of 3:1.
error messages which I would like to hide. Is there a way how to do that? I've done the research but could find anything useful.
Here is my createMuiTheme code
createMuiTheme({
themeName: 'radovix',
palette: {
primary: {
main: '#5EB44B'
}
},
contrastThreshold: 2
});
Note, I'm aware that best approach would be changing the colors that I'm using and therefore solving the error, but that is not possible in my case.
This console error is produced by getContrastText which is used whenever a contrastText color is not explicitly specified.
Instead of specifying contrastThreshold: 2, I would recommend explicitly specifying the desired contrastText color for those cases where the default contrastThreshold of 3 does not pick the one you want. Customization of contrastThreshold is really only intended for increasing the threshold -- not for decreasing it.
Here's a working example:
import React from "react";
import { createMuiTheme, ThemeProvider } from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
import { common } from "#material-ui/core/colors";
const theme = createMuiTheme({
palette: {
primary: {
main: "#5EB44B",
contrastText: common.white
}
}
});
export default function App() {
return (
<ThemeProvider theme={theme}>
<Button color="primary" variant="contained">
Primary Color Button
</Button>
</ThemeProvider>
);
}

Resources