Integrating Material UI into a React NextJS app

Elana Olson
3 min readMar 2, 2024

--

Let’s breakdown how to add Material UI to a NextJS app to get you running with it in no time!

You can view the full change here if you’re impatient 😄, it’s part of a larger project for a react-portfolio-app.

Start by following the general installation guide here where we install Material UI, emotion/react, and emotion/styled for customized css.

yarn add @mui/material @emotion/react @emotion/styled

We can use Emotion styled components to define React components with styling attached to them. This makes our code more readable because everything is in a JSX format and the styling is contained in a reusable component.

Specific configuration changes for NextJS

There are three changes we need to make to the application

  1. Add App Router
  2. Create a theme
  3. Consume the theme in a ThemeProvider client-rendered file

We need to install specific dependencies for NextJS integration with Material UI, which involves using the App Router instead of Page Router.

yarn add @mui/material-nextjs @emotion/cache

1. Add App Router

Add AppRouterCacheProvider to the root layout

// app/layout.tsx
import { AppRouterCacheProvider } from '@mui/material-nextjs/v13-appRouter';

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>
<AppRouterCacheProvider>
{children}
</AppRouterCacheProvider>
</body>
</html>
);
}

2. Create a Theme

Create a file theme.ts and define the theme to be used by the ThemeProvider as outlined in the doc.

// app/theme.ts
'use client';
import { Roboto } from 'next/font/google';
import { createTheme } from '@mui/material/styles';

const roboto = Roboto({
weight: ['300', '400', '500', '700'],
subsets: ['latin'],
display: 'swap',
});

const theme = createTheme({
typography: {
fontFamily: roboto.style.fontFamily,
},
});

export default theme;

3. Consume the theme in a ThemeProvider client-rendered file

Instead of adding the ThemeProvider directly to the root layout.tsx , you’ll need to create a separate file containing ThemeProvider and call that in layout.tsx . We do this because ThemeProvider sets up a client-side context which cannot be rendered server-side, so we pull the code into its own client-rendered file and call it in layout.tsx .

In this new file called StyledRoot.tsx, we start the file with ‘use client’ to signify this is a client-side rendered file (read more here). Here’s what the file will look like:

// app/StyledRoot.tsx
'use client';
import { ThemeProvider } from '@mui/material/styles';
import theme from './theme';

export function StyledRoot({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<ThemeProvider theme={theme}>
{children}
</ThemeProvider>
);
}

Then we add it to layout.tsx which will pass child components through to StyledRoot.tsx

// app/layout.tsx
import { AppRouterCacheProvider } from '@mui/material-nextjs/v13-appRouter';
import { StyledRoot } from './StyledRoot';

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>
<AppRouterCacheProvider>
<StyledRoot>{children}</StyledRoot>
</AppRouterCacheProvider>
</body>
</html>
);
}

And that’s it!

Now you have Material UI up and running with a NextJs app. The next step is to start adding components!

Start by perusing the component library — see what components support your design and look at the code examples for how to implement them!

Another great resource are the Material UI templates which use most of the Material UI components in real world examples. I find these examples to be the most useful — I took a special interest in the Blog template when building my portfolio app.

That’s all folks! Please let me know if you found this article helpful and if it’s missing any important details!

--

--

Elana Olson

Software Engineer who loves learning about web development and working with others to expand the ecosystem.