How can I use useTheme in Material UI 5?
Asked Answered
F

5

23

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:

Please, if someone knows, how do you get the theme in a component in MUI 5?

Foushee answered 19/10, 2021 at 1:39 Comment(4)
@mui/material/styles/useTheme is the correct one to use. It only returns the default theme if you haven't specified a different one via @mui/material/styles/ThemeProvider.Sandy
@RyanCogswell But, I have specified a different one with @mui/material/styles/ThemeProvider... Let me make my question more clear with that. I'll also try to add a MREFoushee
Here's a simple example showing useTheme working: codesandbox.io/s/usetheme-example-bbule?file=/src/App.js.Sandy
@RyanCogswell I found the problem - you cannot use useTheme in the same component that the ThemeProvider is in. Once I made a new component, it worked perfectly fine. Thanks for your example!Foushee
F
22

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.

Foushee answered 19/10, 2021 at 4:38 Comment(3)
sx prop also provides a way to access theme, mui.com/system/basics/#theme-getterAyer
@Ayer Yeah, I was using the useTheme hook for something that can't use the sx prop - this is just an example.Foushee
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 ThemeProviderMirilla
G
8

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.

Godmother answered 14/2, 2022 at 15:4 Comment(0)
K
7

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.

Khoury answered 9/3, 2022 at 17:20 Comment(1)
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 ThemeProviderMirilla
H
1

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

Heavily answered 12/1, 2023 at 5:42 Comment(1)
Damnnnn thank you. Silly mistake, but with VSCode's automatic imports, it's always pulling from @emotion/react instead of MUI.Assonance
M
0

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>
  );
};
Mirilla answered 24/1, 2023 at 0:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.