Using Joy UI and Material UI together
Learn how to use Joy UI and Material UI together in the same project.
Introduction
There are two main use cases for using them together:
- Your existing project already uses Material UI but you're willing to explore the new components and style Joy UI offers.
- You've started your project with Joy UI but you find a key component you need is missing.
Additionally, keep these in mind when using them together:
- Both of them use MUI System as their style engine, which uses React context for theming.
- Theme scoping must be done on one of the libraries.
Prerequisite
- Have
@mui/material
and@mui/joy
installed in your project. - The version of both libraries must be v5.12.0 or higher.
Set up the providers
Render Joy UI's CssVarsProvider
inside Material UI's provider and use THEME_ID
to separate the themes from each other.
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';
import CssBaseline from '@mui/material/CssBaseline';
const materialTheme = materialExtendTheme();
export default function App() {
return (
<MaterialCssVarsProvider theme={{ [MATERIAL_THEME_ID]: materialTheme }}>
<JoyCssVarsProvider>
<CssBaseline enableColorScheme />
...Material UI and Joy UI components
</JoyCssVarsProvider>
</MaterialCssVarsProvider>
);
}
Sync the color mode
To sync the color mode between the providers, call setMode
from both of the libraries:
import { useColorScheme as useJoyColorScheme } from '@mui/joy/styles';
import { useColorScheme as useMaterialColorScheme } from '@mui/material/styles';
const ModeToggle = () => {
const { mode, setMode: setMaterialMode } = useMaterialColorScheme();
const { setMode: setJoyMode } = useJoyColorScheme();
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
// prevent server-side rendering mismatch
// because `mode` is undefined on the server.
return null;
}
return (
<IconButton
onClick={() => {
setMaterialMode(mode === 'dark' ? 'light' : 'dark');
setJoyMode(mode === 'dark' ? 'light' : 'dark');
}}
>
{/** You can use `mode` from Joy UI or Material UI since they are synced **/}
{mode === 'dark' ? <DarkMode /> : <LightMode />}
</IconButton>
);
};
Default mode
If you want to change the defaultMode
, you have to specify the prop to both of the providers:
<MaterialCssVarsProvider
defaultMode="system"
theme={{ [MATERIAL_THEME_ID]: materialTheme }}
>
<JoyCssVarsProvider defaultMode="system">
<CssBaseline enableColorScheme />
...Material UI and Joy UI components
</JoyCssVarsProvider>
</MaterialCssVarsProvider>
Caveat
Both libraries have the same class name prefix:
import MaterialTypography, {
typographyClasses as materialTypographyClasses,
} from '@mui/material/Typography';
import JoyTypography, {
typographyClasses as joyTyographyClasses,
} from '@mui/joy/Typography';
import Stack from '@mui/material/Stack';
<Stack
sx={{
// similar to `& .${joyTyographyClasses.root}`
[`& .${materialTypographyClasses.root}`]: {
color: 'red',
},
}}
>
{/* Both components are red. */}
<MaterialTypography>Red</MaterialTypography>
<JoyTypography>Red</JoyTypography>
</Stack>;
Joy UI and Material UI components have a different name for theming the components. For example, Joy UI's Button uses JoyButton
whereas Material UI's Button uses MuiButton
.