material-ui: Next.js + Material UI v5 styled-component example is still showing className mismatch error

  • [ x] The issue is present in the latest release.
  • [ x] I have searched the issues of this repository and believe that this is not a duplicate.

Current Behavior 😯

I’ve followed the example for nextjs styled-components.

The example works out of the box.

However, once you create a styled-component, the className did not match from server side rendering error will occur.

https://github.com/mui-org/material-ui/tree/75f27074b89381d25a1fab85fc2098af58e89cb0/examples/nextjs-with-styled-components-typescript

Prop className did not match. Server: ā€œsc-dlnjwi fBCjsW MuiBox-rootā€ Client: ā€œsc-gtsrHT kMdZqK MuiBox-rootā€

Expected Behavior šŸ¤”

The example should work like it should.

Steps to Reproduce šŸ•¹

I’ve forked the example ( from above ) with code sandbox.

What I did was to create a simple styled component on index.js (I’m not proficient with ts) and the error will show.

  1. Fork https://github.com/mui-org/material-ui/tree/75f27074b89381d25a1fab85fc2098af58e89cb0/examples/nextjs-with-styled-components-typescript
  2. Create a simple styled component
  3. Restart server (if you are using codesandbox).
  4. See console for error.

I’ve done the above in a sandbox - https://codesandbox.io/s/jolly-yonath-kjxj2?file=/pages/index.js

Context šŸ”¦

I’m using NextJS but I’m not sure how to modify your example to work with Material-ui v5. I think this is the toughest part using NextJS + Material-UI and a solution is necessary.

Your Environment šŸŒŽ

`Material-UI` "@material-ui/core": "^5.0.0-beta.2", "@material-ui/icons": "^5.0.0-beta.1", "@material-ui/lab": "^5.0.0-alpha.41", "@material-ui/styled-engine-sc": "^5.0.0-beta.1", "@material-ui/styles": "^5.0.0-beta.2",
`NEXT.JS` "next-transpile-modules": "^8.0.0", "next": "^11.0.1",
`npx @material-ui/envinfo`
System:
    OS: macOS 11.4
  Binaries:
    Node: 16.5.0 - ~/.nvm/versions/node/v16.5.0/bin/node
    Yarn: Not Found
    npm: 7.19.1 - ~/.nvm/versions/node/v16.5.0/bin/npm
  Browsers:
    Chrome: 92.0.4515.107
    Edge: Not Found
    Firefox: Not Found
    Safari: 14.1.1

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Reactions: 30
  • Comments: 48 (16 by maintainers)

Commits related to this issue

Most upvoted comments

Still having this issue even with the latest examples. Any updates here?

Hi guys, anyone figured out a fix?

https://github.com/mui-org/material-ui/tree/master/examples/nextjs-with-styled-components-typescript has some recents commit, still seeing the errors when developing

Agree, I don’t think that we can expect developers to use the current version of the example. Personally, I wouldn’t as it not really working.

~https://github.com/mui-org/material-ui/pull/27088#issuecomment-885278495 is a working solution.~

As to why the current solution doesn’t work? I don’t know. It would be great to have a deep dive. So far, it seems that styled-components was not designed for SSR.

The problem with this approach is that the SSR part ends up being turned off @Michal-gasiorowski, I’m having the same problem using next + material-5 + makeStyles + npm, I saw several issues reporting this type of issue being caused by various reasons, this ended up leaving me confused about the real status of this issue?

_document.tsx

`import { ServerStyleSheets } from ā€˜@mui/styles’


MyDocument.getInitialProps = async (ctx) => { const sheets = new ServerStyleSheets() ctx.renderPage = () => originalRenderPage({ // eslint-disable-next-line react/display-name enhanceApp: (App: any) => (props) => sheets.collect(<App emotionCache={cache} {…props} />), }) … return { …initialProps, // Styles fragment is rendered after the app and page rendering finish. styles: […React.Children.toArray(initialProps.styles), sheets.getStyleElement()], } }`

Guys, I have edit sandbox example, because it doesn’t reproduce bug. To reproduce bug, styled component must use props

Here is a link to see the bug

https://codesandbox.io/s/charming-rain-oswex?file=/pages/index.js

the same thing to withStyle and makeStyle If u dont use props, it is ok, but once u have used props based styles, bug happens

Our temporary solution until we will migrate from makeStyles

import * as React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import createEmotionServer from '@emotion/server/create-instance';
import { lightTheme } from '../src/theme';
import createEmotionCache from '../src/createEmotionCache';
import { ServerStyleSheets } from '@mui/styles';

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="iw" dir="rtl">
        <Head>
          {/* PWA primary color */}
          <meta name="theme-color" content={lightTheme.palette.primary.main} />
          <link rel="shortcut icon" href="/static/favicon.ico" />
          {/* Inject MUI styles first to match with the prepend: true configuration. */}
          {(this.props as any).emotionStyleTags}
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

MyDocument.getInitialProps = async (ctx) => {
  const originalRenderPage = ctx.renderPage;
  const cache = createEmotionCache();
  const { extractCriticalToChunks } = createEmotionServer(cache);

  const sheets = new ServerStyleSheets();

  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: (App: any) =>
        function EnhanceApp(props) {
          return sheets.collect(<App emotionCache={cache} {...props} />);
        },
    });

  const initialProps = await Document.getInitialProps(ctx);
  const emotionStyles = extractCriticalToChunks(initialProps.html);
  const emotionStyleTags = emotionStyles.styles.map((style) => (
    <style
      data-emotion={`${style.key} ${style.ids.join(' ')}`}
      key={style.key}
      // eslint-disable-next-line react/no-danger
      dangerouslySetInnerHTML={{ __html: style.css }}
    />
  ));

  return {
    ...initialProps,
    styles: [
      ...React.Children.toArray(initialProps.styles),
      sheets.getStyleElement(),
    ],
    emotionStyleTags,
  };
};

Hi again! I was able to get it working with yarn v2.

Followed the implementation in https://github.com/mui-org/material-ui/pull/27583 until I got the problem above, but I solved that problem by upgrading babel-plugin-styled-components to v1.13.3, and it seems to solve the problem overall. Cannot see any warnings any more!

After struggling for a day with a combination of issues (Next.js 12 + MUI v5 + TypeScript + makeStyles), I guess there is a permanent solution (at least for those using emotion as engine and are wiling to use styled api). I think it also works with styled components but can’t be sure since I ran into another error (same mentioned by @mnajdova here);

So… to the possible solution:

While trying to fix the media query thing, I stumbled upon this CodeSandbox, that uses the styled API instead of makeStyles. I also noticed that it uses a <StyledEngineProvider> component with injectFirst property, but after testing it, the use of styled API was enough to prevent the issue.

I will send a PR, adding a styled component to the the emotion example in the next minutes (my first PR here, still unsure of how to proceed, but I’ll give it a try), so that other people can also avoid wasting time on the makeStyles path.

@mnajdova, I’m still unsure of how to tackle the issue but it is worth mentioning that the issue is the same, following both, styled-components and emotion examples.

Detailed steps to reproduce:

  • (Terminal) Clone any of the available examples of nextjs + mui + typescript, (emotion or styled-components)

  • (Terminal) Install dependencies:

        yarn
    
  • (Terminal) Add @mui/styles dependency to use makeStyles:

     yarn add @mui/styles
    
  • (/pages/index) Import makeStyles and define classes:

    • ps: using media queries here since breakpoints + typescript + useStyles was leading to another error;
    
       // pages/index.tsx
    
       import Box from '@mui/material/Box';
       import Container from '@mui/material/Container';
       import Typography from '@mui/material/Typography';
       import { makeStyles } from '@mui/styles';
       import * as React from 'react';
       import Copyright from '../src/Copyright';
       import Link from '../src/Link';
       import ProTip from '../src/ProTip';
       
       export default function Index() {
       
         const classes = makeStyles(() => ({
           container: {
             '@media (max-width: 600px)': {
               fontSize: 20'vw'
             },
             '@media (min-width: 601px)': {
               fontSize: '7rem'
             }
           }
         }))();
       
         return (
           <Container maxWidth="sm" className={classes.container}>
             <Box sx={{ my: 4 }}>
               <Typography variant="h4" component="h1" gutterBottom>
                 Next.js v5-beta with TypeScript example
               </Typography>
               <Link href="/about" color="secondary">
                 Go to the about page
               </Link>
               <ProTip />
               <Copyright />
             </Box>
           </Container>
         );
       }
    
    • (Terminal) Run project:
       yarn dev
    
    • (Browser) Access app on http://localhost:3000;
    • (Browser: DevTools) Set window to responsive and drag to force the media query responsive font size changes;
    • (Browser) āœ”ļø Verify that it is all running as expected ;
    • (Browser) Click on ā€˜Go to the about page’ link;
    • (Browser) āœ”ļø Verify that is all running as expected;
    • (Browser) Click to go back on the browser ā€˜back’ arrow;
    • (Browser) Refresh the page (F5);
    • (Browser) āŒ Verify that the style broke and the following error appear on the console:
      Warning: Prop `className` did not match. Server: "MuiContainer-root MuiContainer-maxWidthSm makeStyles-container-2 css-cuefkz-MuiContainer-root" Client: "MuiContainer-root MuiContainer-maxWidthSm makeStyles-container-1 css-cuefkz-MuiContainer-root"
          at div
          at eval (webpack-internal:///./node_modules/@emotion/react/dist/emotion-element-99289b21.browser.esm.js:55:66)
          at Container (webpack-internal:///./node_modules/@mui/material/Container/Container.js:93:83)
          at Index (webpack-internal:///./pages/index.tsx:32:19)
          at InnerThemeProvider (webpack-internal:///./node_modules/@mui/system/esm/ThemeProvider/ThemeProvider.js:21:70)
          at ThemeProvider (webpack-internal:///./node_modules/@mui/private-theming/ThemeProvider/ThemeProvider.js:47:5)
          at ThemeProvider (webpack-internal:///./node_modules/@mui/system/esm/ThemeProvider/ThemeProvider.js:41:5)
          at MyApp (webpack-internal:///./pages/_app.tsx:57:27)
          at StyleRegistry (webpack-internal:///./node_modules/styled-jsx/dist/stylesheet-registry.js:231:34)
          at ErrorBoundary (webpack-internal:///./node_modules/@next/react-dev-overlay/lib/internal/ErrorBoundary.js:26:47)
          at ReactDevOverlay (webpack-internal:///./node_modules/@next/react-dev-overlay/lib/internal/ReactDevOverlay.js:90:23)
          at Container (webpack-internal:///./node_modules/next/dist/client/index.js:305:9)
          at AppContainer (webpack-internal:///./node_modules/next/dist/client/index.js:745:26)
          at Root (webpack-internal:///./node_modules/next/dist/client/index.js:866:27)
      printWarning @ react-dom.development.js?ac89:67
      error @ react-dom.development.js?ac89:43
      warnForPropDifference @ react-dom.development.js?ac89:8824
      diffHydratedProperties @ react-dom.development.js?ac89:9645
      hydrateInstance @ react-dom.development.js?ac89:10400
      prepareToHydrateHostInstance @ react-dom.development.js?ac89:14616
      completeWork @ react-dom.development.js?ac89:19458
      completeUnitOfWork @ react-dom.development.js?ac89:22815
      performUnitOfWork @ react-dom.development.js?ac89:22787
      workLoopSync @ react-dom.development.js?ac89:22707
      renderRootSync @ react-dom.development.js?ac89:22670
      performSyncWorkOnRoot @ react-dom.development.js?ac89:22293
      scheduleUpdateOnFiber @ react-dom.development.js?ac89:21881
      updateContainer @ react-dom.development.js?ac89:25482
      eval @ react-dom.development.js?ac89:26021
      unbatchedUpdates @ react-dom.development.js?ac89:22431
      legacyRenderSubtreeIntoContainer @ react-dom.development.js?ac89:26020
      hydrate @ react-dom.development.js?ac89:26086
      renderReactElement @ index.js?46cb:488
      doRender @ index.js?46cb:709
      _callee$ @ index.js?46cb:384
      tryCatch @ runtime.js?2d8a:45
      invoke @ runtime.js?2d8a:274
      prototype.<computed> @ runtime.js?2d8a:97
      asyncGeneratorStep @ index.js?46cb:31
      _next @ index.js?46cb:49
      eval @ index.js?46cb:54
      eval @ index.js?46cb:46
      _render @ index.js?46cb:403
      render @ index.js?46cb:406
      eval @ next-dev.js?3515:76
      eval @ fouc.js?0087:12
      requestAnimationFrame (async)
      displayContent @ fouc.js?0087:7
      eval @ next-dev.js?3515:75
      Promise.then (async)
      eval @ next-dev.js?3515:38
      ./node_modules/next/dist/client/next-dev.js @ main.js?ts=1635690486095:578
      options.factory @ webpack.js?ts=1635690486095:633
      __webpack_require__ @ webpack.js?ts=1635690486095:37
      __webpack_exec__ @ main.js?ts=1635690486095:1247
      (anonymous) @ main.js?ts=1635690486095:1248
      webpackJsonpCallback @ webpack.js?ts=1635690486095:1179
      (anonymous) @ main.js?ts=1635690486095:9
      Show 2 more frames
    

My environment:

node: v16.13.0 yarn: v1.22.10

Still having this issue even with the latest examples. Any updates here?

just use emotion, there’s no issue with emotion.

But it is happening with emotion.

Still having this issue even with the latest examples. Any updates here?

just use emotion, there’s no issue with emotion.

See https://github.com/mui-org/material-ui/issues/29742#issuecomment-982597676 I am starting to think that we should maybe rather recommend emotion for SSR projects. There are just so many issues using styled-components with external library.

Credits to @Janpot for the investigation around this.

@mnajdova Thanks for the answer, I tried to use Yarn but still got the same error after one refresh

For me on npm: '7.21.0' just putting this in package.json worked in dev and prod without any errors:

"dependencies": {
    "@mui/material": "^5.0.0",
    "@mui/icons-material": "^5.0.0",
    "@mui/lab": "^5.0.0-alpha.47",
    "@mui/styled-engine-sc": "^5.0.0",
    "@mui/styles": "^5.0.0",
    ...,
    "next": "^11.1.2",
    ...
    "styled-components": "^5.3.1",
},
"alias": {
    "@mui/styled-engine": "@mui/styled-engine-sc"
},

(and also having usual collectStyles in the _document and like 3 providers in the _app)

I’m styling with import styled from "styled-components";.

Warning: Did not expect server HTML to contain a <style> in <div>.

In every page refresh