| name | mui |
| description | Material-UI component library patterns including sx prop styling, theme integration, responsive design, and MUI-specific hooks. Use when working with MUI components (@mui/material), styling with sx prop, theme customization, or MUI utilities. Supports v5, v6, and v7. |
MUI Patterns
Purpose
Material-UI patterns for component usage, styling with sx prop, theme integration, and responsive design. This skill supports MUI v5, v6, and v7.
Version Detection
Before applying patterns, check the project's MUI version:
grep '"@mui/material"' package.json
Then apply version-specific guidance:
- v5.x: See v5-notes.md for v5-specific patterns
- v7.x: See v7-changes.md for v7 breaking changes
- v6.x: Use v7 patterns (most are compatible)
When to Use This Skill
- Styling components with MUI sx prop
- Using MUI components (Box, Grid, Paper, Typography, etc.)
- Theme customization and usage
- Responsive design with MUI breakpoints
- MUI-specific utilities and hooks
Quick Start
Basic MUI Component
import { Box, Typography, Button, Paper } from '@mui/material';
import type { SxProps, Theme } from '@mui/material';
const styles: Record<string, SxProps<Theme>> = {
container: {
p: 2,
display: 'flex',
flexDirection: 'column',
gap: 2,
},
header: {
mb: 3,
fontSize: '1.5rem',
fontWeight: 600,
},
};
function MyComponent() {
return (
<Paper sx={styles.container}>
<Typography sx={styles.header}>
Title
</Typography>
<Button variant="contained">
Action
</Button>
</Paper>
);
}
Styling Patterns
Inline Styles (< 100 lines)
For components with simple styling, define styles at the top:
import type { SxProps, Theme } from '@mui/material';
const componentStyles: Record<string, SxProps<Theme>> = {
container: {
p: 2,
display: 'flex',
flexDirection: 'column',
},
header: {
mb: 2,
color: 'primary.main',
},
button: {
mt: 'auto',
alignSelf: 'flex-end',
},
};
function Component() {
return (
<Box sx={componentStyles.container}>
<Typography sx={componentStyles.header}>Header</Typography>
<Button sx={componentStyles.button}>Action</Button>
</Box>
);
}
Separate Styles File (>= 100 lines)
For complex components, create separate style file:
import type { SxProps, Theme } from '@mui/material';
export const userProfileStyles: Record<string, SxProps<Theme>> = {
container: {
p: 3,
maxWidth: 800,
mx: 'auto',
},
header: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
mb: 3,
},
};
import { userProfileStyles as styles } from './UserProfile.styles';
function UserProfile() {
return <Box sx={styles.container}>...</Box>;
}
Common Components
Layout Components
<Box sx={{ p: 2, bgcolor: 'background.paper' }}>
Content
</Box>
<Paper elevation={2} sx={{ p: 3 }}>
Content
</Paper>
<Container maxWidth="lg">
Content
</Container>
<Stack spacing={2} direction="row">
<Item />
<Item />
</Stack>
Grid System
Note: Grid API differs by version. See version-specific notes.
import { Grid } from '@mui/material';
<Grid container spacing={2}>
<Grid item xs={12} md={6}>
Left half
</Grid>
<Grid item xs={12} md={6}>
Right half
</Grid>
</Grid>
import Grid from '@mui/material/Grid2';
<Grid container spacing={2}>
<Grid xs={12} md={6}>
Left half
</Grid>
<Grid xs={12} md={6}>
Right half
</Grid>
</Grid>
Typography
<Typography variant="h1">Heading 1</Typography>
<Typography variant="h2">Heading 2</Typography>
<Typography variant="body1">Body text</Typography>
<Typography variant="caption">Small text</Typography>
<Typography
variant="h4"
sx={{
color: 'primary.main',
fontWeight: 600,
mb: 2,
}}
>
Custom Heading
</Typography>
Buttons
<Button variant="contained">Contained</Button>
<Button variant="outlined">Outlined</Button>
<Button variant="text">Text</Button>
<Button variant="contained" color="primary">Primary</Button>
<Button variant="contained" color="secondary">Secondary</Button>
<Button variant="contained" color="error">Error</Button>
import { Add as AddIcon } from '@mui/icons-material';
<Button startIcon={<AddIcon />}>Add Item</Button>
Theme Integration
Using Theme Values
import { useTheme } from '@mui/material';
function Component() {
const theme = useTheme();
return (
<Box
sx={{
p: 2,
bgcolor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
borderRadius: theme.shape.borderRadius,
}}
>
Themed box
</Box>
);
}
Theme in sx Prop
<Box
sx={{
color: 'primary.main',
bgcolor: 'background.paper',
p: 2,
borderRadius: 1,
}}
>
Content
</Box>
<Box
sx={(theme) => ({
color: theme.palette.primary.main,
'&:hover': {
color: theme.palette.primary.dark,
},
})}
>
Hover me
</Box>
Responsive Design
Breakpoints
<Box
sx={{
width: {
xs: '100%',
sm: '80%',
md: '60%',
lg: '40%',
xl: '30%',
},
}}
>
Responsive width
</Box>
<Box
sx={{
display: {
xs: 'none', // Hidden on mobile
md: 'block', // Visible on desktop
},
}}
>
Desktop only
</Box>
Responsive Typography
<Typography
sx={{
fontSize: {
xs: '1rem',
md: '1.5rem',
lg: '2rem',
},
lineHeight: {
xs: 1.5,
md: 1.75,
},
}}
>
Responsive text
</Typography>
Forms
import { TextField, Stack, Button } from '@mui/material';
<Box component="form" onSubmit={handleSubmit}>
<Stack spacing={2}>
<TextField
label="Email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
fullWidth
required
error={!!errors.email}
helperText={errors.email}
/>
<Button type="submit" variant="contained">Submit</Button>
</Stack>
</Box>
Common Patterns
Card Component
import { Card, CardContent, CardActions, Typography, Button } from '@mui/material';
<Card>
<CardContent>
<Typography variant="h5" component="div">
Title
</Typography>
<Typography variant="body2" color="text.secondary">
Description
</Typography>
</CardContent>
<CardActions>
<Button size="small">Learn More</Button>
</CardActions>
</Card>
Dialog/Modal
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';
function MyDialog({ open, onClose }) {
const handleClose = (event, reason) => {
if (reason === 'backdropClick') {
return;
}
onClose();
};
return (
<Dialog open={open} onClose={handleClose}>
<DialogTitle>Confirm Action</DialogTitle>
<DialogContent>
Are you sure you want to proceed?
</DialogContent>
<DialogActions>
<Button onClick={onClose}>Cancel</Button>
<Button onClick={handleConfirm} variant="contained">
Confirm
</Button>
</DialogActions>
</Dialog>
);
}
Loading States
import { CircularProgress, Skeleton } from '@mui/material';
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
<CircularProgress />
</Box>
<Stack spacing={1}>
<Skeleton variant="text" width="60%" />
<Skeleton variant="rectangular" height={200} />
<Skeleton variant="text" width="40%" />
</Stack>
Component Customization (slots/slotProps)
<Autocomplete
slots={{
paper: CustomPaper,
}}
slotProps={{
paper: { elevation: 8 },
}}
/>
<Autocomplete
components={{
Paper: CustomPaper,
}}
componentsProps={{
paper: { elevation: 8 },
}}
/>
For new code, always use slots/slotProps.
MUI-Specific Hooks
useMuiSnackbar
import { useMuiSnackbar } from '@/hooks/useMuiSnackbar';
function Component() {
const { showSuccess, showError, showInfo } = useMuiSnackbar();
const handleSave = async () => {
try {
await saveData();
showSuccess('Saved successfully');
} catch (error) {
showError('Failed to save');
}
};
return <Button onClick={handleSave}>Save</Button>;
}
Icons
import { Add as AddIcon, Delete as DeleteIcon } from '@mui/icons-material';
import { Button, IconButton } from '@mui/material';
<Button startIcon={<AddIcon />}>Add</Button>
<IconButton onClick={handleDelete}><DeleteIcon /></IconButton>
Best Practices
1. Type Your sx Props
import type { SxProps, Theme } from '@mui/material';
const styles: Record<string, SxProps<Theme>> = {
container: { p: 2 },
};
const styles = {
container: { p: 2 },
};
2. Use Theme Tokens
<Box sx={{ color: 'primary.main', p: 2 }} />
<Box sx={{ color: '#1976d2', padding: '16px' }} />
3. Consistent Spacing
<Box sx={{ p: 2, mb: 3, mt: 1 }} />
<Box sx={{ padding: '17px', marginBottom: '25px' }} />
4. Import Patterns
import { Button, Box, Typography } from '@mui/material';
import Button from '@mui/material/Button';
import createTheme from '@mui/material/styles/createTheme';
Additional Resources
For more detailed patterns, see: