Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useTheme doesn't reflect custom theme values when used with Remix SSR setup #31233

Open
2 tasks done
Tracked by #39765
nikola1912 opened this issue Feb 27, 2022 · 6 comments
Open
2 tasks done
Tracked by #39765
Labels
examples Relating to /examples

Comments

@nikola1912
Copy link

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Current behavior 😯

Used Remix + MUI example as a base without any changes. I tried using the useTheme hook in Copyright component so I can use custom theme values defined in createTheme, but the theme object from useTheme doesn't contain values defined in the custom theme object.

Console logging the theme object from useTheme shows correct values on the server, but wrong values in the browser.

The bug happens in any component but here's how I encountered it in Copyright.ts file:

import Typography from "@mui/material/Typography";
import Link from "@mui/material/Link";
import { useTheme } from "@mui/material";

export default function Copyright() {
  const theme = useTheme();

  console.log(theme);

  return (
    <Typography variant="body2" color="text.secondary" align="center">
      {"Copyright © "}
      <Link color="inherit" href="https://mui.com/">
        Your Website
      </Link>{" "}
      {new Date().getFullYear()}.
    </Typography>
  );
}

How theme.ts file looks:

import { createTheme } from "@mui/material/styles";
import { red } from "@mui/material/colors";

// Create a theme instance.
const theme = createTheme({
  palette: {
    primary: {
      main: "#556cd6",
    },
    secondary: {
      main: "#19857b",
    },
    error: {
      main: red.A400,
    },
  },
});

export default theme;

Expected behavior 🤔

Resulting theme object from useTheme should reflect any values defined in the custom theme object passed to createTheme.

Steps to reproduce 🕹

Steps:

  1. Clone the Remix + MUI example repo:
curl https://codeload.github.com/mui/material-ui/tar.gz/master | tar -xz --strip=2  material-ui-master/examples/remix-with-typescript
cd remix-with-typescript
  1. Copy the code from Current behavior section into app/src/Copyright.tsx file
  2. Start the app with npm run dev, open the browser and check the console

Context 🔦

Remix + MUI example

Your environment 🌎

`npx @mui/envinfo`
System:
    OS: macOS 11.3.1
  Binaries:
    Node: 16.9.1 - /usr/local/bin/node
    Yarn: 1.22.10 - /opt/homebrew/bin/yarn
    npm: 7.20.1 - /opt/homebrew/bin/npm
  Browsers:
    Chrome: 98.0.4758.109
    Edge: Not Found
    Firefox: 96.0.2
    Safari: 14.1
  npmPackages:
    @emotion/react: latest => 11.8.1 
    @emotion/styled: latest => 11.8.1 
    @mui/base:  5.0.0-alpha.69 
    @mui/material: latest => 5.4.3 
    @mui/private-theming:  5.4.2 
    @mui/styled-engine:  5.4.2 
    @mui/system:  5.4.3 
    @mui/types:  7.1.2 
    @mui/utils:  5.4.2 
    @types/react: latest => 17.0.39 
    react: latest => 17.0.2 
    react-dom: latest => 17.0.2 
    typescript: latest => 4.5.5
@nikola1912 nikola1912 added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Feb 27, 2022
@danilo-leal danilo-leal added examples Relating to /examples and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Feb 28, 2022
@totszwai
Copy link

totszwai commented May 25, 2022

Mui: v5.8.1

I think there is a problem with useTheme it is returning the systemDefaultTheme and not the custom theme object that is currently in the ThemeProvider.

When I debug my code, Mui's useTheme was going into here:

export const systemDefaultTheme = createTheme();

My expectation is that, it would supposed to go in this different useTheme instead and grab the proper theme object from the context?

const theme = React.useContext(ThemeContext);

I have code like this, my component tried to grab the theme using useTheme:

import { useTheme } from '@mui/material/styles';

const Blah = () => {
  const theme = useTheme<MyCustomThemePalette>();
  // this returns the default theme object without any of my custom definition
  console.log(theme);
}

I have the following custom provider which, when dumping the incoming theme object, it has everything I defined, but not in the children.

import { ThemeProvider as MuiThemeProvider, CssBaseline, StyledEngineProvider } from '@mui/material';
import { ThemeProvider } from 'styled-components';

export const MyThemeProvider = (props: React.PropsWithChildren<MyThemeOptions>) => {
  let theme = props.theme;
  console.debug('[MyThemeProvider] theme?', theme);

  return (
    <StyledEngineProvider injectFirst>
      <MuiThemeProvider theme={props.theme}>
        <ThemeProvider theme={props.theme}>
          <>
            <GlobalStyle />
            <CssBaseline />
            <Blah />
            {props.children}
          </>
        </ThemeProvider>
      </MuiThemeProvider>
    </StyledEngineProvider>
  );
};

In fact, even within my GlobalStyle level, styled-components was able to return the proper theme object with my custom definitions, but not when using useTheme.

import { createGlobalStyle, css } from 'styled-components';
const GlobalStyle = createGlobalStyle`
  ${({ theme }: MyThemeOptions) => {
    console.debug('[GlobalStyle] theme?', theme); // <==== prints the proper theme object
    const globalStyle = css`
      ${require('../assets/styles/index.css')}
      ${generateRootCssVariables(theme)}
      ${TypographyStyle(theme)}
    `;
    // console.debug(globalStyle);
    return globalStyle;
  }}`;

Is this related?

`npx @mui/envinfo`
  System:
    OS: Linux 5.13 Ubuntu 21.10 21.10 (Impish Indri)
  Binaries:
    Node: 14.19.2 - ~/.config/nvm/versions/node/v14.19.2/bin/node
    Yarn: Not Found
    npm: 6.14.17 - ~/.config/nvm/versions/node/v14.19.2/bin/npm
  Browsers:
    Chrome: 101.0.4951.64
    Firefox: 100.0.2
  npmPackages:
    @emotion/react: ^11.9.0 => 11.9.0 
    @emotion/styled: ^11.8.1 => 11.8.1 
    @mui/base:  5.0.0-alpha.82 
    @mui/material: ^5.8.1 => 5.8.1 
    @mui/private-theming:  5.8.0 
    @mui/styled-engine:  5.8.0 
    @mui/styled-engine-sc: ^5.8.0 => 5.8.0 
    @mui/system:  5.8.1 
    @mui/types:  7.1.3 
    @mui/utils:  5.8.0 
    @types/react: ^17.0.2 => 17.0.2 
    react: ^17.0.2 => 17.0.2 
    react-dom: ^17.0.2 => 17.0.2 
    styled-components: ^5.3.5 => 5.3.5 
    typescript: ^4.6.4 => 4.6.4 

@Eyon42
Copy link

Eyon42 commented Nov 28, 2022

This also happens with Next.js SSR.
Just using the hook throws hydration errors and I get the default theme on the frontend.

@W01fw00d
Copy link

W01fw00d commented Feb 3, 2023

In our project (with SRR and custom Module Federation config), we were able to replicate this same issue.

"@mui/material" useTheme doesn't return our custom theme (we just get the default Mui theme instead), but "@mui/material/styles" styled returns our custom theme just fine. They doesn't seem to work in a consistent way as we would expect (theme should be the always the same one that the Provider defines, on both mui fns).

totszwai message seems to be on the right direction from my POV. Let me know if you need more details to solve this 🙂. Thanks!

EDIT: what we did in our case is to add "@mui/system" as a singleton to our webpack config. Because of our Module Federation, it seems 2 versions of this library were loaded and conflicting. Not sure if it's related to this issue, but mentioning it here in case it helps somebody.

@michaeltford
Copy link

I am able to reproduce this using storybook 7. useTheme always returns the system theme (but styled() works correctly.

@michaeltford
Copy link

After quite of bit of effort I was able to get past this and the related issue #32806. @W01fw00d My resolution was similar my resolution.

@GermaVinsmoke
Copy link

GermaVinsmoke commented Aug 1, 2024

I think I was able to solve this issue. Using MUI version - 5.10.16. Please mind the code formatting.

// muiTheme.d.ts

import { Palette } from '@mui/material';
import { Palette, PaletteColor, Theme, ThemeOptions, useTheme } from '@mui/material/styles';

declare module '@mui/material/styles' {
export interface CustomPalette extends Palette {
	warning: CustomPaletteColor;
}

export interface CustomPaletteColor extends PaletteColor {
	medium?: string;
}

interface CustomPalette extends Palette {
	warning?: CustomPaletteColor;
}

interface CustomPaletteColor extends PaletteColor {
	medium?: string;
}

export interface CustomTheme extends Theme {
         palette: CustomPalette;
}
        
export interface CustomThemeOptions extends ThemeOptions {
         palette: CustomPalette;
}
        
export function createTheme(options?: CustomThemeOptions): CustomTheme;

export function useTheme<T = CustomTheme>(): CustomTheme;
}
// theme.ts

import { CustomPalette, createTheme } from '@mui/material/styles';

const muiDefaultTheme = createTheme();

const palette: CustomPalette = {
	...muiDefaultTheme.palette,
	warning: {
		light: '#f9d884',
		main: '#ffc020',
		medium: '#f29a0f',
		dark: '#e97500',
		background: '#fef5dc',
		contrastText: '#ffffff',
	},
}

export const theme = createTheme({
	palette,
});
Screenshot 2024-08-01 at 11 43 25

[EDIT] - Sorry, noticed it now that the issue is for Remix SSR, not sure if it will work with it or not but for a normal React project, I think it'll work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
examples Relating to /examples
Projects
None yet
Development

No branches or pull requests

7 participants