Search code examples
material-uistyled-componentsnext.js

How to integrate Nextjs + styled-components with material-ui


1. To build a next.js app using styled components it's really easy. You just have to use their _document.js snippet to enable SSR and prevent styles flickering on page load: https://github.com/zeit/next.js/blob/canary/examples/with-styled-components/pages/_document.js

2. To build a next.js app using material-ui is almost as simple. You just have to start with ther project base: https://github.com/mui-org/material-ui/tree/master/examples/nextjs, which has its own implementation on _document.js: https://github.com/mui-org/material-ui/blob/master/examples/nextjs/pages/_document.js

3. Sadly, I couldn't figure out how to "merge" both implementations and get a next app where both styled-components and material-ui components can coexist, SSR and do not flicker on page load.

Can you help me? Is there someone on the internet with better abilities than mine whom already solved that problem but I do not know about?

Thanks in advance.


Solution

  • Give this a try

    _document.js

    import React from 'react';
    import Document, { Head, Main, NextScript } from 'next/document';
    import { ServerStyleSheet } from 'styled-components'
    import { ServerStyleSheets } from '@material-ui/styles';
    import theme from '../src/theme';
    
    class MyDocument extends Document {
      static async getInitialProps (ctx) {
        const styledComponentsSheet = new ServerStyleSheet()
        const materialSheets = new ServerStyleSheets()
        const originalRenderPage = ctx.renderPage;
    
        try {
            ctx.renderPage = () => originalRenderPage({
                enhanceApp: App => props => styledComponentsSheet.collectStyles(materialSheets.collect(<App {...props} />))
              })
            const initialProps = await Document.getInitialProps(ctx)
            return {
              ...initialProps,
              styles: (
                <React.Fragment>
                  {initialProps.styles}
                  {materialSheets.getStyleElement()}
                  {styledComponentsSheet.getStyleElement()}
                </React.Fragment>
              )
            }
          } finally {
            styledComponentsSheet.seal()
          }
      }
    
      render() {
        return (
          <html lang="en" dir="ltr">
            <Head>
              <meta charSet="utf-8" />
              {/* Use minimum-scale=1 to enable GPU rasterization */}
              <meta
                name="viewport"
                content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
              />
              {/* PWA primary color */}
              <meta
                name="theme-color"
                content={theme.palette.primary.main}
              />
              <link
                rel="stylesheet"
                href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
              />
            </Head>
            <body>
              <Main />
              <NextScript />
            </body>
          </html>
        );
      }
    }
    
    export default MyDocument;
    

    .babelrc

    {
      "presets": ["next/babel"],
      "plugins": [["styled-components", { "ssr": true }]]
    }
    

    For update check https://github.com/nblthree/nextjs-with-material-ui-and-styled-components