mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
93.73k stars 32.23k forks source link

[Joy] How to work with both `@mui/material` and `@mui/joy` in `Next.js` #35644

Closed GodsonAddy closed 1 year ago

GodsonAddy commented 1 year ago

Hello Guys! I'm already using @mui/material in my nextjs app but I would like to use @mui/joy also because of its RadioGroup. Whenever I try to use any of the @mui/joy components, I get an error. This error differs from each other depending on the particular component I want to use

Example of error

error - TypeError: Cannot read properties of undefined (reading 'radius')
    at C:\BLOOP\bloop2.0_frontend\node_modules\@mui\joy\node\RadioGroup\RadioGroup.js:53:30
    at transformedStyleArg (C:\admin\blog_app\node_modules\@mui\system\createStyled.js:190:18)
    at handleInterpolation (C:\admin\blog_app\node_modules\@emotion\serialize\dist\emotion-serialize.cjs.dev.js:149:24)
    at Object.serializeStyles (C:\admin\blog_app\node_modules\@emotion\serialize\dist\emotion-serialize.cjs.dev.js:274:15)
    at C:\admin\blog_app\node_modules\@emotion\styled\base\dist\emotion-styled-base.cjs.dev.js:148:34
    at C:\admin\blog_app\node_modules\@emotion\react\dist\emotion-element-b63ca7c6.cjs.dev.js:66:16
    at renderWithHooks (C:\admin\blog_app\node_modules\react-dom\cjs\react-dom-server.browser.development.js:5658:16)
    at renderIndeterminateComponent (C:\admin\blog_app\node_modules\react-dom\cjs\react-dom-server.browser.development.js:5731:15)
    at renderElement (C:\admin\blog_app\node_modules\react-dom\cjs\react-dom-server.browser.development.js:5946:7)
    at renderNodeDestructiveImpl (C:\admin\blog_app\node_modules\react-dom\cjs\react-dom-server.browser.development.js:6104:11)

pages/radio-button.js

import React from "react";
import List from "@mui/joy/List";
import ListItem from "@mui/joy/ListItem";
import Radio from "@mui/joy/Radio";
import RadioGroup from "@mui/joy/RadioGroup";

export const default RadioButtons = () => {
return (
<div>
<RadioGroup
        aria-label="Your plan"
        name="people"
        defaultValue="Individual"
      >
        <List
          sx={{
            minWidth: 240,
            "--List-gap": "0.5rem",
            "--List-item-paddingY": "1rem",
            "--List-item-radius": "8px",
            "--List-decorator-size": "32px",
          }}
        >
          {["Individual", "Team", "Enterprise"].map((item, index) => (
            <ListItem
              variant="outlined"
              key={item}
              sx={{ boxShadow: "sm", bgcolor: "background.body" }}
            >
              <Radio
                overlay
                value={item}
                label={item}
                sx={{ flexGrow: 1, flexDirection: "row-reverse" }}
                slotProps={{
                  action: ({ checked }) => ({
                    sx: (theme) => ({
                      ...(checked && {
                        inset: -1,
                        border: "2px solid",
                        borderColor: theme.vars.palette.primary[500],
                      }),
                    }),
                  }),
                }}
              />
            </ListItem>
          ))}
        </List>
      </RadioGroup>
</div>
```js

pages/_app.js
```js
import "../styles/globals.css";
import PropTypes from "prop-types";
import Head from "next/head";
import React from "react";
import { ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import { CacheProvider } from "@emotion/react";
import theme from "../src/theme";
import createEmotionCache from "../src/createEmotionCache";

const clientSideEmotionCache = createEmotionCache();
function MyApp(props) {
  const {
    Component,
    emotionCache = clientSideEmotionCache,
    pageProps: { session, ...pageProps },
  } = props;
  return (
          <CacheProvider value={emotionCache}>
            <Head>
              <meta
                name="viewport"
                content="initial-scale=1, width=device-width"
              />
            </Head>
            <ThemeProvider theme={theme}>
              {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
              <CssBaseline />
                <Component {...pageProps} />
            </ThemeProvider>
          </CacheProvider>

  );
}

MyApp.propTypes = {
  Component: PropTypes.elementType.isRequired,
  emotionCache: PropTypes.object,
  pageProps: PropTypes.object.isRequired,
};

export default MyApp;

pages/_document.js

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

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <Head>
          {/* PWA primary color */}
          <meta name="theme-color" content={theme.palette.primary.main} />
          <link rel="shortcut icon" href="/favicon.ico" />
          <link rel="preconnect" href="https://fonts.googleapis.com" />
          <link
            rel="preconnect"
            href="https://fonts.gstatic.com"
            crossOrigin="true"
          />
          <link
            href="https://fonts.googleapis.com/css2?family=Jost&family=League+Spartan&family=Poppins&display=swap"
            rel="stylesheet"
          />
          <meta name="emotion-insertion-point" content="" />
          {this.props.emotionStyleTags}
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

MyDocument.getInitialProps = async (ctx) => {

  const originalRenderPage = ctx.renderPage;

  const cache = createEmotionCache();
  const { extractCriticalToChunks } = createEmotionServer(cache);

  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: (App) =>
        function EnhanceApp(props) {
          return <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,
    emotionStyleTags,
  };
};

src/createEmotionCache.js

import createCache from "@emotion/cache";

const isBrowser = typeof document !== "undefined";

export default function createEmotionCache() {
  let insertionPoint;

  if (isBrowser) {
    const emotionInsertionPoint = document.querySelector(
      'meta[name="emotion-insertion-point"]'
    );
    insertionPoint = emotionInsertionPoint ?? undefined;
  }

  return createCache({ key: "mui-style", insertionPoint });
}

src/theme.js

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

// Create a theme instance.
const theme = createTheme({
  typography: {
    button: {
      textTransform: "none",
    },
    Jost: {
      fontFamily: '"Jost", serif',
    },
    Poppins: {
      fontFamily: '"Poppins", serif',
    },
    fontFamily: ["League Spartan"].join(","),
    palette: {
      primary: "#FFFFFF",
      secondary: "4A4D4E",
    },
  },
  palette: {
    primary: {
      main: "#F55C6E",
    },
    secondary: {
      main: "#fff",
    },
    tertiary: {
      main: "#000",
    },
  },
});

export default theme;

package.json

   "@emotion/react": "^11.10.5",
    "@emotion/server": "^11.10.0",
    "@emotion/styled": "^11.10.5",
    "@mui/base": "^5.0.0-alpha.102",
    "@mui/icons-material": "^5.10.6",
    "@mui/joy": "^5.0.0-alpha.60",
    "@mui/lab": "^5.0.0-alpha.103",
    "@mui/material": "^5.10.8",
    "@mui/system": "^5.10.10",
hbjORbj commented 1 year ago

It doesn't look like this bug report has enough info for one of us to reproduce it.


Please provide a CodeSandbox (https://material-ui.com/r/issue-template-latest), a link to a repository on GitHub, or provide a minimal code example that reproduces the problem.

Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve

GodsonAddy commented 1 year ago

This is a link to the repo: https://github.com/GodsonAddy/next-project

chasingbubbles commented 1 year ago

I'm having a similar issue when trying to use the Textarea of Joy. Not sure if this also has something to do with Joy not working with Material for som reason.

I've just added this to my code:

image

image

And I get this error: image

siriwatknp commented 1 year ago

@GodsonAddy @chasingbubbles Have you followed the guide on how to use both of them together?

https://mui.com/joy-ui/guides/using-joy-ui-and-material-ui-together/

GodsonAddy commented 1 year ago

Will check it out @siriwatknp

GodsonAddy commented 1 year ago

Actually, the guide worked for me. Everything is working fine now and this is how it looks like now.

src/theme.js

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

// Create a theme instance.
const theme = createTheme({
  typography: {
    button: {
      textTransform: "none",
    },
    Jost: {
      fontFamily: '"Jost", serif',
    },
    fontFamily: ["League Spartan"].join(","),
    palette: {
      primary: "#FFFFFF",
      secondary: "4A4D4E",
    },
  },
  palette: {
    primary: {
      main: "#F55C6E",
    },
    secondary: {
      main: "#fff",
    },
    tertiary: {
      main: "#000",
    },
  },
});

export default theme;

pages/_app.js

import "../styles/globals.css";
import PropTypes from "prop-types";
import Head from "next/head";
import React from "react";
import CssBaseline from "@mui/material/CssBaseline";
import { CacheProvider } from "@emotion/react";
import theme from "../src/theme";
import createEmotionCache from "../src/createEmotionCache";
import { deepmerge } from "@mui/utils";
import {
  useColorScheme,
  Experimental_CssVarsProvider as CssVarsProvider,
  experimental_extendTheme as extendMuiTheme,
} from "@mui/material/styles";
import { extendTheme as extendJoyTheme } from "@mui/joy/styles";
import { blue, grey } from "@mui/material/colors";

const muiTheme = extendMuiTheme(theme);  //theme from "../src/theme";

const joyTheme = extendJoyTheme({
  // This is required to point to `var(--mui-*)` because we are using
  // `CssVarsProvider` from Material UI.
  cssVarPrefix: "mui",
  colorSchemes: {
    light: {
      palette: {
        primary: {
          ...blue,
          solidColor: "var(--mui-palette-primary-contrastText)",
          solidBg: "var(--mui-palette-primary-main)",
          solidHoverBg: "var(--mui-palette-primary-dark)",
          plainColor: "var(--mui-palette-primary-main)",
          plainHoverBg:
            "rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-hoverOpacity))",
          plainActiveBg: "rgba(var(--mui-palette-primary-mainChannel) / 0.3)",
          outlinedBorder: "rgba(var(--mui-palette-primary-mainChannel) / 0.5)",
          outlinedColor: "var(--mui-palette-primary-main)",
          outlinedHoverBg:
            "rgba(var(--mui-palette-primary-mainChannel) / var(--mui-palette-action-hoverOpacity))",
          outlinedHoverBorder: "var(--mui-palette-primary-main)",
          outlinedActiveBg:
            "rgba(var(--mui-palette-primary-mainChannel) / 0.3)",
        },
        neutral: {
          ...grey,
        },
        // Do the same for the `danger`, `info`, `success`, and `warning` palettes,
        divider: "var(--mui-palette-divider)",
        text: {
          tertiary: "rgba(0 0 0 / 0.56)",
        },
      },
    },
    // Do the same for dark mode
    // dark: { ... }
  },
  fontFamily: {
    display: '"Roboto","Helvetica","Arial",sans-serif',
    body: '"Roboto","Helvetica","Arial",sans-serif',
  },
  shadow: {
    xs: `var(--mui-shadowRing), ${muiTheme.shadows[1]}`,
    sm: `var(--mui-shadowRing), ${muiTheme.shadows[2]}`,
    md: `var(--mui-shadowRing), ${muiTheme.shadows[4]}`,
    lg: `var(--mui-shadowRing), ${muiTheme.shadows[8]}`,
    xl: `var(--mui-shadowRing), ${muiTheme.shadows[12]}`,
  },
});

// Note: you can't put `joyTheme` inside Material UI's `extendMuiTheme(joyTheme)`
// because some of the values in the Joy UI theme refers to CSS variables and
// not raw colors.

// You can use your own `deepmerge` function.
// muiTheme will deeply merge to joyTheme.

const allTheme = deepmerge(joyTheme, muiTheme);

const clientSideEmotionCache = createEmotionCache();
function MyApp(props) {
  const {
    Component,
    emotionCache = clientSideEmotionCache,
    pageProps: { session, ...pageProps },
  } = props;
  return (

          <CacheProvider value={emotionCache}>

            <Head>
              <meta
                name="viewport"
                content="initial-scale=1, width=device-width"
              />
            </Head>

            <CssVarsProvider theme={allTheme}>
              {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
              <CssBaseline />
                <Component {...pageProps} />
            </CssVarsProvider>
          </CacheProvider>
         );
}

MyApp.propTypes = {
  Component: PropTypes.elementType.isRequired,
  emotionCache: PropTypes.object,
  pageProps: PropTypes.object.isRequired,
};

export default MyApp;

And if there's a better way to do it, please let me know.

ZeeshanAhmadKhalil commented 1 year ago

@siriwatknp i have followed the doc to merge joy into mui but still getting the same error

siriwatknp commented 1 year ago

@siriwatknp i have followed the doc to merge joy into mui but still getting the same error

Can you share a CodeSandbox or a repository that I can take a look?

suruicq commented 1 year ago

image image get error

siriwatknp commented 1 year ago

@suruicq Please check the latest docs again https://mui.com/joy-ui/integrations/material-ui/.

nlarusstone commented 11 months ago

I'm following the docs, but still seeing a similar error when trying to integrate in this way. We're using the pages dir, not app dir.

My code in _app.tsx:

import {
  experimental_extendTheme as materialExtendTheme,
  Experimental_CssVarsProvider as MaterialCssVarsProvider,
  THEME_ID as MATERIAL_THEME_ID,
} from "@mui/material/styles";
import { CssVarsProvider as JoyCssVarsProvider } from "@mui/joy/styles";
const materialTheme = materialExtendTheme();

...
                    <MaterialCssVarsProvider
                      theme={{ [MATERIAL_THEME_ID]: materialTheme }}
                    >
                      <JoyCssVarsProvider>
                        {getLayout(<Component {...pageProps} />)}
                      </JoyCssVarsProvider>
                    </MaterialCssVarsProvider>
...

Error:

TypeError: Cannot read properties of undefined (reading 'fontFamily')

Call Stack
createTypography
node_modules/@mui/material/styles/createTypography.js (20:0)
resolveTheme
node_modules/@mui/material/styles/CssVarsProvider.js (26:34)
CssVarsProvider
node_modules/@mui/system/esm/cssVars/createCssVarsProvider.js (254:0)
renderWithHooks
node_modules/react-dom/cjs/react-dom.development.js (16305:0)
mountIndeterminateComponent
node_modules/react-dom/cjs/react-dom.development.js (20074:0)
beginWork
node_modules/react-dom/cjs/react-dom.development.js (21587:0)
HTMLUnknownElement.callCallback
node_modules/react-dom/cjs/react-dom.development.js (4164:0)
Object.invokeGuardedCallbackDev
node_modules/react-dom/cjs/react-dom.development.js (4213:0)
invokeGuardedCallback
node_modules/react-dom/cjs/react-dom.development.js (4277:0)
beginWork$1
node_modules/react-dom/cjs/react-dom.development.js (27451:0)
performUnitOfWork
node_modules/react-dom/cjs/react-dom.development.js (26557:0)
workLoopSync
node_modules/react-dom/cjs/react-dom.development.js (26466:0)
renderRootSync
node_modules/react-dom/cjs/react-dom.development.js (26434:0)
performConcurrentWorkOnRoot
node_modules/react-dom/cjs/react-dom.development.js (25738:0)
workLoop
node_modules/scheduler/cjs/scheduler.development.js (266:0)
flushWork
node_modules/scheduler/cjs/scheduler.development.js (239:0)
MessagePort.performWorkUntilDeadline
node_modules/scheduler/cjs/scheduler.development.js (533:0)

Packages:

"@emotion/react": "^11.11.1",
    "@emotion/styled": "^11.11.0",
    "@fontsource/inter": "^5.0.15",
 "@mui/joy": "^5.0.0-beta.13",
    "@mui/material": "^5.14.16",
    "next": "^13.2.0",
so0601pk commented 7 months ago

I'm following the docs, but still seeing a similar error when trying to integrate in this way. We're using the pages dir, not app dir.

My code in _app.tsx:

import {
  experimental_extendTheme as materialExtendTheme,
  Experimental_CssVarsProvider as MaterialCssVarsProvider,
  THEME_ID as MATERIAL_THEME_ID,
} from "@mui/material/styles";
import { CssVarsProvider as JoyCssVarsProvider } from "@mui/joy/styles";
const materialTheme = materialExtendTheme();

...
                    <MaterialCssVarsProvider
                      theme={{ [MATERIAL_THEME_ID]: materialTheme }}
                    >
                      <JoyCssVarsProvider>
                        {getLayout(<Component {...pageProps} />)}
                      </JoyCssVarsProvider>
                    </MaterialCssVarsProvider>
...

Error:

TypeError: Cannot read properties of undefined (reading 'fontFamily')

Call Stack
createTypography
node_modules/@mui/material/styles/createTypography.js (20:0)
resolveTheme
node_modules/@mui/material/styles/CssVarsProvider.js (26:34)
CssVarsProvider
node_modules/@mui/system/esm/cssVars/createCssVarsProvider.js (254:0)
renderWithHooks
node_modules/react-dom/cjs/react-dom.development.js (16305:0)
mountIndeterminateComponent
node_modules/react-dom/cjs/react-dom.development.js (20074:0)
beginWork
node_modules/react-dom/cjs/react-dom.development.js (21587:0)
HTMLUnknownElement.callCallback
node_modules/react-dom/cjs/react-dom.development.js (4164:0)
Object.invokeGuardedCallbackDev
node_modules/react-dom/cjs/react-dom.development.js (4213:0)
invokeGuardedCallback
node_modules/react-dom/cjs/react-dom.development.js (4277:0)
beginWork$1
node_modules/react-dom/cjs/react-dom.development.js (27451:0)
performUnitOfWork
node_modules/react-dom/cjs/react-dom.development.js (26557:0)
workLoopSync
node_modules/react-dom/cjs/react-dom.development.js (26466:0)
renderRootSync
node_modules/react-dom/cjs/react-dom.development.js (26434:0)
performConcurrentWorkOnRoot
node_modules/react-dom/cjs/react-dom.development.js (25738:0)
workLoop
node_modules/scheduler/cjs/scheduler.development.js (266:0)
flushWork
node_modules/scheduler/cjs/scheduler.development.js (239:0)
MessagePort.performWorkUntilDeadline
node_modules/scheduler/cjs/scheduler.development.js (533:0)

Packages:

"@emotion/react": "^11.11.1",
    "@emotion/styled": "^11.11.0",
    "@fontsource/inter": "^5.0.15",
 "@mui/joy": "^5.0.0-beta.13",
    "@mui/material": "^5.14.16",
    "next": "^13.2.0",

We are experiencing similar problems

so0601pk commented 7 months ago

The similar problems resolved. My project configured Material UI theme. So I set it up this way.

_app.page.tsx

const theme = createTheme({
  components: {
    MuiTextField: {
      styleOverrides: {
        root: {
         // theme config
        },
      },
    },
  },
})

function MyApp({ Component, pageProps }: AppProps) {
  return (
      <ThemeProvider theme={theme}>
        <MaterialCssVarsProvider>
          <JoyCssVarsProvider>
              <CssBaseline enableColorScheme />
              <Component {...pageProps} />
          </JoyCssVarsProvider>
        </MaterialCssVarsProvider>
      </ThemeProvider>
  )
}