| name | material-ui |
| description | Material-UI (MUI) v7 React component library - components, theming, customization, best practices |
| metadata | {"language":"typescript","audience":"developers"} |
Overview
Material-UI (MUI) v7 is the latest version of the popular React component library implementing Google's Material Design. Use this skill when working with MUI components.
Current Version: v7.3.9
Installation
npm install @mui/material @emotion/react @emotion/styled
Peer Dependencies
{
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
}
}
Icons
npm install @mui/icons-material
Roboto Font
npm install @fontsource/roboto
Import in entry point:
import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';
React 18 and Below
If using React 18 or below, set react-is override:
{
"overrides": {
"react-is": "^18.3.1"
}
}
Quickstart
import Button from '@mui/material/Button';
export default function App() {
return <Button variant="contained">Hello World</Button>;
}
Required Globals
Add to your app:
import { CssBaseline, ThemeProvider } from '@mui/material';
Viewport meta tag:
<meta name="viewport" content="initial-scale=1, width=device-width" />
Theming
Create Theme
import { createTheme } from '@mui/material/styles';
const theme = createTheme({
palette: {
mode: 'dark',
primary: { main: '#1976d2' },
secondary: { main: '#dc004e' },
},
typography: {
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
},
spacing: 8,
});
Apply Theme
import { ThemeProvider, CssBaseline } from '@mui/material';
function App({ children }) {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
{children}
</ThemeProvider>
);
}
Dark Mode with CSS Variables
const theme = createTheme({
cssVariables: {
colorSchemeSelector: 'class',
},
colorSchemes: {
light: true,
dark: true,
},
});
Use theme.vars.* for CSS variables:
const StyledDiv = styled('div')(({ theme }) => ({
color: theme.vars.palette.text.primary,
}));
Color Scheme with useColorScheme
MUI v7 provides useColorScheme hook to manage color modes (light/dark/system) without explicit state management. Pair with a custom useMode hook for cleaner separation of concerns.
1. Create the theme with color schemes:
import { createTheme } from '@mui/material/styles';
const theme = createTheme({
cssVariables: {
colorSchemeSelector: 'class',
},
colorSchemes: {
light: true,
dark: true,
},
palette: {
primary: { main: '#1976d2' },
secondary: { main: '#dc004e' },
},
});
2. Wrap your app with ThemeProvider:
import { ThemeProvider, CssBaseline } from '@mui/material';
function App() {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<YourApp />
</ThemeProvider>
);
}
3. Create a useMode hook for cleaner access:
import { useColorScheme } from '@mui/material/styles';
type Mode = 'light' | 'dark' | 'system';
export function useMode() {
const { mode, setMode, systemMode } = useColorScheme();
return {
mode: mode === 'system' ? systemMode : mode,
modeRaw: mode,
setMode,
isDark: (mode === 'system' ? systemMode : mode) === 'dark',
};
}
4. Use in your TopBar component:
import { AppBar, Toolbar, Typography, IconButton } from '@mui/material';
import { useMode } from './hooks/useMode';
import LightMode from '@mui/icons-material/LightMode';
import DarkMode from '@mui/icons-material/DarkMode';
import SettingsBrightness from '@mui/icons-material/SettingsBrightness';
function TopBar() {
const { modeRaw, setMode } = useMode();
const cycleMode = () => {
const modes: Array<'light' | 'dark' | 'system'> = ['light', 'dark', 'system'];
const currentIndex = modes.indexOf(modeRaw);
setMode(modes[(currentIndex + 1) % modes.length]);
};
return (
<AppBar position="static">
<Toolbar>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
My App
</Typography>
<IconButton color="inherit" onClick={cycleMode}>
{modeRaw === 'dark' ? <LightMode /> : modeRaw === 'light' ? <DarkMode /> : <SettingsBrightness />}
</IconButton>
</Toolbar>
</AppBar>
);
}
5. Use in any component:
import { useMode } from './hooks/useMode';
import { Box, Typography } from '@mui/material';
function Dashboard() {
const { isDark, mode } = useMode();
return (
<Box sx={{ bgcolor: isDark ? 'grey.900' : 'grey.100', p: 2 }}>
<Typography>Current mode: {mode}</Typography>
</Box>
);
}
Customization
1. One-off: sx Prop
<Button sx={{ width: 300, bgcolor: 'success.main' }}>
Custom
</Button>
2. Nested Styles
<Slider sx={{ '& .MuiSlider-thumb': { borderRadius: 1 } }} />
3. Reusable: styled()
import Slider, { SliderProps } from '@mui/material/Slider';
import { styled } from '@mui/material/styles';
const SuccessSlider = styled(Slider)<SliderProps>(({ theme }) => ({
color: theme.palette.success.main,
}));
4. Dynamic Props
interface CustomSliderProps extends SliderProps {
success?: boolean;
}
const StyledSlider = styled(Slider, {
shouldForwardProp: (prop) => prop !== 'success',
})<CustomSliderProps>(({ success, theme }) => ({
...(success && { color: theme.palette.success.main }),
}));
5. Global Theme Overrides
const theme = createTheme({
components: {
MuiButton: {
defaultProps: { disableElevation: true },
styleOverrides: {
root: { textTransform: 'none' },
},
},
},
});
Component Patterns
Slot Props (MUI v7 Standard)
<Accordion
slots={{ transition: CustomTransition }}
slotProps={{ transition: { unmountOnExit: true } }}
/>
Responsive Design
<Box sx={{
display: 'flex',
flexDirection: { xs: 'column', md: 'row' },
gap: { xs: 1, md: 2 },
}} />
Grid (v2 - now just Grid)
import Grid from '@mui/material/Grid';
<Grid container spacing={2}>
<Grid item xs={12} md={6}>Content</Grid>
</Grid>
Stack (Preferred over Box for Simple Layouts)
<Stack direction="row" spacing={2}>
<Button>One</Button>
<Button>Two</Button>
</Stack>
State Classes
Use for hover, focus, disabled, selected states:
.Mui-active, .Mui-checked, .Mui-disabled, .Mui-error, .Mui-expanded, .Mui-focusVisible, .Mui-focused, .Mui-readOnly, .Mui-required, .Mui-selected
<Button disabled className="CustomButton">
Migration to v7
Key Changes
- Grid2 → Grid: Use
import Grid from '@mui/material/Grid'
- Lab components: Import from
@mui/material not @mui/lab
- createMuiTheme → createTheme
- InputLabel size="normal" → size="medium"
- Deep imports removed: Use
import { createTheme } from '@mui/material/styles'
- Hidden component removed: Use
sx prop or useMediaQuery
Codemods
npx @mui/codemod v7.0.0/grid-props <path>
npx @mui/codemod v7.0.0/lab-removed-components <path>
npx @mui/codemod v7.0.0/input-label-size-normal-medium <path>
Icons
Import individually for tree-shaking:
import Home from '@mui/icons-material/Home';
import Search from '@mui/icons-material/Search';
Use sx for sizing:
<Home sx={{ fontSize: 24, color: 'primary.main' }} />
Common Components
| Component | Use Case |
|---|
| Box | Generic wrapper |
| Container | Page layout |
| Stack | Simple layouts |
| Grid | Complex layouts |
| Button | Actions |
| TextField | Form inputs |
| Card | Content containers |
| AppBar | Navigation headers |
| Drawer | Side navigation |
| Dialog | Modals |
| Table | Data grids |
| Chip | Tags/labels |
| Typography | Text styling |
| Avatar | User images |
| Alert | Notifications |
| Skeleton | Loading states |
| Menu | Dropdown menus |
| Tabs | Tab navigation |
| Stepper | Multi-step forms |
Best Practices
- Use Theme - Define colors, typography, spacing globally
- Use sx for One-off - Quick style overrides
- Use styled() for Reusable - Create custom components
- Use Stack - Prefer over Box for simple layouts
- Use Grid (v2) - For complex responsive layouts
- Use CSS Variables - For better dev tools and dark mode
- Use Slot Props - MUI v7 standard for component customization
- TypeScript - MUI v7 requires TypeScript 4.9+
- Test - Use
@mui/internal/test-utils for testing
- Top Bar with Color Scheme Switch - Use AppBar with Toolbar, Typography for title, and useColorScheme hook for theme toggle
import { AppBar, Toolbar, Typography, IconButton } from '@mui/material';
import { useColorScheme } from '@mui/material/styles';
import LightMode from '@mui/icons-material/LightMode';
import DarkMode from '@mui/icons-material/DarkMode';
function TopBar() {
const { mode, setMode } = useColorScheme();
return (
<AppBar position="static">
<Toolbar>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
My App
</Typography>
<IconButton color="inherit" onClick={() => setMode(mode === 'dark' ? 'light' : 'dark')}>
{mode === 'dark' ? <LightMode /> : <DarkMode />}
</IconButton>
</Toolbar>
</AppBar>
);
}