How can I use useTheme in Material UI 5? - reactjs

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

Related

Can not use ubuntu-mono font in chakra-UI

I'm trying to use the ubuntu-mono font in react with chakra-UI. So, I referred to the chakra-UI [docs][1].
However, the change could not be reflected.
My ```theme.ts``` and ```App.tsx``` are below.
theme.ts
import { extendTheme } from "#chakra-ui/react";
const theme = extendTheme({
fonts: {
heading: "Ubuntu-mono",
body: "Ubuntu-mono",
},
styles: {
global: {
body: {
backgroundColor: "black",
color: "white",
}
}
}
})
export default theme;
App.tsx
import * as React from "react"
import {
ChakraProvider, Container,
} from "#chakra-ui/react"
import {BrowserRouter} from "react-router-dom";
import theme from "./theme/theme";
import '#fontsource/ubuntu-mono/700.css';
import {Router} from "./router/Router";
export const App = () => (
<ChakraProvider theme={theme}>
<BrowserRouter>
<Router/>
</BrowserRouter>
</ChakraProvider>
)
Of course, I have run npm install with the package.json that includes the "#fontsource/ubuntu-mono": "^4.5.6" line in its dependencies.
I also referred to another doc of the chakra-UI, however, I could not find out describes regarding this problem.
Although, this may an easy problem, anyone who gives me a solution.
I'm guessing this has to do with the environment. I tried it initially in CodeSandbox but the font didn't load but when I ran it locally using Vite app, it worked just fine.
What environment are you working in? See my repo here: https://github.com/estheragbaje/test-fonts

Set MUI Theme for Specific React Page

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>

Property 'palette' is not recognised by DefaultTheme from MaterialUI, it stopped to work once material ui have been moved from v4 to v5

I'm moving app from Material UI v4 to v5 and I'm facing few issues.
One of them is that property 'palette' in not recognised by DefaultTheme from Material UI once it's used in makeStyles. That component worked properly in v4, but once I moved majority to v5 it shows me an error now and don't recognise 'palette' property. Can You please look at it and let me know how to fix it ?
this is how it's called in main component:
import { makeStyles } from '#mui/styles';
const useStyles = makeStyles((theme) => ({
styledButton: {
'&': { color: theme.palette.cerulean },
'&.Mui-selected': {
backgroundColor: theme.palette.aliceBlue,
color: theme.palette.cerulean,
},
'&:hover': {
backgroundColor: 'rgba(227,245,255, 0.5) !important',
},
},
}));
When I hover over above 'palette' TS give a comment like: Property 'palette' does not exist on type 'DefaultTheme'.
Theme is called in App as below:
import { ThemeProvider } from '#mui/styles';
import { MainTheme } from '#nevomo/utilities';
export const App: FC = () => (
<StyledEngineProvider injectFirst>
<ThemeProvider theme={MainTheme}>
<SCThemeProvider theme={MainTheme}>
<CssBaseline />
<Router>
<AuthContextProvider>
<Notifications />
<RoutingManager />
</AuthContextProvider>
</Router>
</SCThemeProvider>
</ThemeProvider>
</StyledEngineProvider>
);
MainTheme looks like:
import { createTheme, Theme } from '#mui/material/styles';
import { paletteColors } from './main-theme-colors';
export const MainTheme: Theme = createTheme({
spacing: (factor: number) => `${factor * 1}rem`,
palette: {
primary: {
main: paletteColors.primary.main,
},
secondary: {
main: paletteColors.secondary.main,
},
error: {
main: paletteColors.error.main,
},
white: '#FFFFFF',
lighterBlue: '#EFFBFF',
lightBlue: '#DEF7FF',
celeste: '#00A7E1',
blue: '#0027d3',
navy: '#083D77',
greenSalad: '#4DA167',
red: '#d32f2f',
pink: '#FFE3E3',
lightPink: '#ECD6E6',
darkPink: '#700353',
black: '#000000',
orange: '#FD5C01',
darkRed: '#AD160B',
aliceBlue: '#E3F5FF',
cerulean: '#007CBA',
},
});
thanks a lot !
The OP resolved their issue, but I'll leave this from the MUI migration documentation for future people facing the same problem:
[Types] Property "palette", "spacing" does not exist on type 'DefaultTheme'
Since makeStyles is now exported from #mui/styles package which does
not know about Theme in the core package. To fix this, you need to
augment the DefaultTheme (empty object) in #mui/styles with Theme from
the core.
TypeScript Project
Put this snippet to your theme file:
// it could be your App.tsx file or theme file that is included in your tsconfig.json
import { Theme } from '#mui/material/styles';
declare module '#mui/styles/defaultTheme' {
// eslint-disable-next-line #typescript-eslint/no-empty-interface (remove this line if you don't have the rule enabled)
interface DefaultTheme extends Theme {}
}
Javascript Project
If your IDE (ex. VSCode) is able to infer types from d.ts file,
create index.d.ts in your src folder with this snippet:
// index.d.ts
declare module "#mui/private-theming" {
import type { Theme } from "#mui/material/styles";
interface DefaultTheme extends Theme {}
}
Current MUI version fixes the DefaultTheme type error this way—
// global.d.ts
import { Theme } from '#mui/material/styles';
declare module '#mui/system' {
interface DefaultTheme extends Theme {}
}
I'm using v4 and I was hitting this issue.
The issue was because I was using
import { useTheme } from '#material-ui/styles';
instead of
import { useTheme } from '#material-ui/core/styles';

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

Material-UI injectFirst doesn't work with storybook

I'm using material-UI with styled-components and according to documentation, in order to override material styles it's required to add this injectFirst attribute:
however when trying to use this approach inside storybook environment it does not work as expected and the JSS styles are still injected after styled-components.
.storybook/config.js:
import React from 'react'
import {configure, addDecorator} from '#storybook/react'
import { StylesProvider } from '#material-ui/styles'
addDecorator(storyFn => (
<StylesProvider injectFirst>
{ storyFn() }
</StylesProvider>
));
const req = require.context('../packages', true, /.story.js$/);
function loadStories() {
req.keys().forEach((filename) => req(filename));
}
configure(loadStories, module);
DOM:
styled-components style attribute is still before JSS
I was not using styled-components, but for MUI + CSS Modules with Storybook v6 the following configuration made it so MUI styles were not overriding our own styles.
.storybook/preview.js:
import { StylesProvider } from '#material-ui/styles'
export const decorators = [
(Story) => (
<StylesProvider injectFirst>
{Story()}
</StylesProvider>
),
]
We had exiting config for parameters in that file from another add-on and I just put the above code in there with it no problem. You may also need to import React in there too depending on how you have things setup (we did not).

Resources