mui
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:
// UserProfile.styles.ts
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,
},
// ... many more styles
};
// UserProfile.tsx
import { userProfileStyles as styles } from './UserProfile.styles';
function UserProfile() {
return <Box sx={styles.container}>...</Box>;
}
Common Components
Layout Components
// Box - Generic container
<Box sx={{ p: 2, bgcolor: 'background.paper' }}>
Content
</Box>
// Paper - Elevated surface
<Paper elevation={2} sx={{ p: 3 }}>
Content
</Paper>
// Container - Centered content with max-width
<Container maxWidth="lg">
Content
</Container>
// Stack - Flex container with spacing
<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';
// v5/v6: Use container + item pattern
<Grid container spacing={2}>
<Grid item xs={12} md={6}>
Left half
</Grid>
<Grid item xs={12} md={6}>
Right half
</Grid>
</Grid>
// v7: Grid2 is now stable, item prop removed
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>
// With custom styling
<Typography
variant="h4"
sx={{
color: 'primary.main',
fontWeight: 600,
mb: 2,
}}
>
Custom Heading
</Typography>
Buttons
// Variants
<Button variant="contained">Contained</Button>
<Button variant="outlined">Outlined</Button>
<Button variant="text">Text</Button>
// Colors
<Button variant="contained" color="primary">Primary</Button>
<Button variant="contained" color="secondary">Secondary</Button>
<Button variant="contained" color="error">Error</Button>
// With icons
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={{
// Access theme in sx
color: 'primary.main', // theme.palette.primary.main
bgcolor: 'background.paper', // theme.palette.background.paper
p: 2, // theme.spacing(2)
borderRadius: 1, // theme.shape.borderRadius
}}
>
Content
</Box>
// Callback for advanced usage
<Box
sx={(theme) => ({
color: theme.palette.primary.main,
'&:hover': {
color: theme.palette.primary.dark,
},
})}
>
Hover me
</Box>
Responsive Design
Breakpoints
// Mobile-first responsive values
<Box
sx={{
width: {
xs: '100%', // 0-600px
sm: '80%', // 600-900px
md: '60%', // 900-1200px
lg: '40%', // 1200-1536px
xl: '30%', // 1536px+
},
}}
>
Responsive width
</Box>
// Responsive display
<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';
// Use onClose with reason checking (works in all versions)
function MyDialog({ open, onClose }) {
const handleClose = (event, reason) => {
// Optional: prevent closing on backdrop click
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';
// Spinner
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
<CircularProgress />
</Box>
// Skeleton
<Stack spacing={1}>
<Skeleton variant="text" width="60%" />
<Skeleton variant="rectangular" height={200} />
<Skeleton variant="text" width="40%" />
</Stack>
Component Customization (slots/slotProps)
// Preferred pattern (works in v5+, required in v7)
<Autocomplete
slots={{
paper: CustomPaper,
}}
slotProps={{
paper: { elevation: 8 },
}}
/>
// Legacy pattern (v5 only, deprecated in v6+)
<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';
// ✅ Good
const styles: Record<string, SxProps<Theme>> = {
container: { p: 2 },
};
// ❌ Avoid
const styles = {
container: { p: 2 }, // No type safety
};
2. Use Theme Tokens
// ✅ Good: Use theme tokens
<Box sx={{ color: 'primary.main', p: 2 }} />
// ❌ Avoid: Hardcoded values
<Box sx={{ color: '#1976d2', padding: '16px' }} />
3. Consistent Spacing
// ✅ Good: Use spacing scale
<Box sx={{ p: 2, mb: 3, mt: 1 }} />
// ❌ Avoid: Random pixel values
<Box sx={{ padding: '17px', marginBottom: '25px' }} />
4. Import Patterns
// ✅ Good: Package-level imports (tree-shakeable)
import { Button, Box, Typography } from '@mui/material';
// ⚠️ v5 only: Second-level imports work
import Button from '@mui/material/Button';
// ❌ v7: Deep imports no longer work
// ❌ All versions: Third-level imports are private API
import createTheme from '@mui/material/styles/createTheme';
Additional Resources
For more detailed patterns, see:
- styling-guide.md - Advanced styling patterns
- component-library.md - Component examples
- theme-customization.md - Theme setup
- v5-notes.md - MUI v5-specific guidance
- v7-changes.md - MUI v7 breaking changes
More from bnadlerjr/dotfiles
slicing-elephant-carpaccio
Breaks features into ultra-thin vertical slices using Elephant Carpaccio methodology. Use when planning new features, breaking down epics, slicing work across layers, or when a task spans multiple components. Produces an ordered backlog of thin slices, each independently working, testable, and demoable. Handles single-repo, monorepo, and multi-repo architectures.
14receiving-code-review
Guides technical evaluation of code review feedback before implementation. Use when receiving PR comments, review suggestions, GitHub feedback, or when asked to address reviewer feedback. Emphasizes verification and reasoned pushback over blind agreement.
13breaking-down-stories
Breaks down user stories into small, actionable tasks. Use when decomposing user stories, planning sprint work, creating task lists from tickets, or when the user mentions story breakdown, task decomposition, or sprint planning.
12applying-swiss-design
Applies Swiss/International Typographic Style principles to create clear, functional output. Use when designing interfaces, data visualizations, documentation, CLI output, or any output where clarity matters. Recognizes requests like "make it cleaner", "reduce clutter", "too busy", "improve readability", "visual hierarchy", "simplify the layout".
1coding-workflow
Use when user asks to build a feature, implement something new, or make significant code changes. Recognizes requests like "build", "implement", "create a new feature", "add functionality", "develop", "I need to build X", "let's implement", "new feature request", "make these changes". Orchestrates a four-stage workflow (Research → Brainstorm → Plan → Implement) using the appropriate thought pattern skill at each stage.
1practicing-tdd
Enforces test-first development with Red-Green-Refactor cycle. Use when implementing features, fixing bugs, writing tests, or when someone mentions TDD, test-driven, "test first", or "write a failing test".
1