Setup


Step 1: Environment

  • Vite.js
  • React v18
  • MUI v6

Step 2: Install dependencies

Dependencies
npm install \
@emotion/cache \
@emotion/react \
@emotion/styled \
@mui/lab \
@mui/material \
@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 vite-js or vite-ts to your current project.

  • Copy and override tsconfig.json / jsconfig.json.
  • Copy and override tsconfig.node.json.
  • Copy src/theme.
  • Remove src/theme/with-settings.
  • Update vite.config.(js | ts).
// vite.config.(js | ts)
 
import path from 'path';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
 
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: [
      {
        find: /^~(.+)/,
        replacement: path.resolve(process.cwd(), 'node_modules/$1'),
      },
      {
        find: /^src(.+)/,
        replacement: path.resolve(process.cwd(), 'src/$1'),
      },
    ],
  },
});

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/theme/create-theme.js
 
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
 
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>
  )
}

Step 6: Testing

  • src/main.(jsx | tsx).
  • src/App.(jsx | tsx).
// src/main.jsx
 
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
 
ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

// src/App.(jsx | tsx)
 
import './global.css';
import { themeConfig, ThemeProvider } from './theme';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
 
export default function App() {
  return (
    <ThemeProvider
      noSsr
      defaultMode={themeConfig.defaultMode}
      modeStorageKey={themeConfig.modeStorageKey}
    >
    <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>
    </ThemeProvider>
  );
}