Setup


Step 1: Environment

  • Next.js v14 (next-app-dir)
  • React v18
  • MUI v6

Step 2: Install dependencies

Dependencies
npm install \
@emotion/cache \
@emotion/react \
@emotion/styled \
@mui/lab \
@mui/material \
@mui/material-nextjs \
@mui/x-tree-view \
@fontsource-variable/public-sans \
@fontsource/barlow \
minimal-shared

Dev dependencies (TypeScript only)
npm i -D @types/node

Step 3: Copy and modifying files

Copy and override files from next-js or next-ts to your current project.

  • Copy and override tsconfig.json / jsconfig.json.
  • Copy src/theme.
  • Remove src/theme/with-settings.

Step 4: Create files

  • src/global.css
@import '@fontsource-variable/public-sans';
@import '@fontsource/barlow/400.css';
@import '@fontsource/barlow/500.css';
@import '@fontsource/barlow/600.css';
@import '@fontsource/barlow/700.css';
@import '@fontsource/barlow/800.css';
 
html {
  height: 100%;
  -webkit-overflow-scrolling: touch;
}
body,
#root,
#root__layout {
  display: flex;
  flex: 1 1 auto;
  min-height: 100%;
  flex-direction: column;
}
img {
  max-width: 100%;
  vertical-align: middle;
}
ul {
  margin: 0;
  padding: 0;
  list-style-type: none;
}
input[type='number'] {
  -moz-appearance: textfield;
  appearance: none;
}
input[type='number']::-webkit-outer-spin-button {
  margin: 0;
  -webkit-appearance: none;
}
input[type='number']::-webkit-inner-spin-button {
  margin: 0;
  -webkit-appearance: none;
}

Step 5: Update theme

  • src/theme/create-theme.(js | ts).
  • src/theme/theme-provider.(jsx | tsx).
  • src/app/layout.(jsx | tsx).
// src/theme/create-theme.js
 
"use client"
 
import { createTheme as createMuiTheme } from "@mui/material/styles";
import { mixins } from "./core/mixins";
import { shadows } from "./core/shadows";
import { palette } from "./core/palette";
import { themeConfig } from "./theme-config";
import { components } from "./core/components";
import { typography } from "./core/typography";
import { customShadows } from "./core/custom-shadows";
 
export const baseTheme = {
  colorSchemes: {
    light: {
      palette: palette.light,
      shadows: shadows.light,
      customShadows: customShadows.light
    },
    dark: {
      palette: palette.dark,
      shadows: shadows.dark,
      customShadows: customShadows.dark
    }
  },
  mixins,
  components,
  typography,
  shape: { borderRadius: 8 },
  direction: themeConfig.direction,
  cssVariables: themeConfig.cssVariables,
  defaultColorScheme: themeConfig.defaultMode
}
 
export function createTheme({ themeOverrides = {} } = {}) {
  const theme = createMuiTheme(baseTheme, themeOverrides)
 
  return theme
}

// src/theme/theme-provider.jsx
 
'use client';
 
import CssBaseline from "@mui/material/CssBaseline";
import { ThemeProvider as ThemeVarsProvider } from "@mui/material/styles";
import { createTheme } from "./create-theme";
 
export function ThemeProvider({ themeOverrides, children, ...other }) {
  const theme = createTheme({ themeOverrides })
 
  return (
    <ThemeVarsProvider disableTransitionOnChange theme={theme} {...other}>
      <CssBaseline />
      {children}
    </ThemeVarsProvider>
  )
}

// src/app/layout.jsx
 
import "src/globals.css"
 
import InitColorSchemeScript from "@mui/material/InitColorSchemeScript";
import { AppRouterCacheProvider } from "@mui/material-nextjs/v14-appRouter";
import { themeConfig, ThemeProvider } from "src/theme";
 
export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app"
}
 
export default function RootLayout({ children }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <InitColorSchemeScript
          defaultMode={themeConfig.defaultMode}
          modeStorageKey={themeConfig.modeStorageKey}
          attribute={themeConfig.cssVariables.colorSchemeSelector}
        />
        <AppRouterCacheProvider options={{ key: "css" }}>
          <ThemeProvider
            defaultMode={themeConfig.defaultMode}
            modeStorageKey={themeConfig.modeStorageKey}
          >
            {children}
          </ThemeProvider>
        </AppRouterCacheProvider>
      </body>
    </html>
  )
}

Step 6: Testing

  • src/app/page.(jsx | tsx).
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
 
export default function Home() {
  return (
    <Box sx={{ p: 5, gap: 2, display: 'flex', justifyContent: 'center' }}>
      <Button variant="contained">Button</Button>
      <Button variant="contained" color="primary">
        Button
      </Button>
      <Button variant="contained" color="secondary">
        Button
      </Button>
      <Button variant="contained" color="info">
        Button
      </Button>
      <Button variant="contained" color="success">
        Button
      </Button>
      <Button variant="contained" color="warning">
        Button
      </Button>
      <Button variant="contained" color="error">
        Button
      </Button>
      <Button disabled variant="contained">
        Button
      </Button>
    </Box>
  );
}