Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Material-UI v7 component library patterns including sx prop styling, theme integration, responsive design, and MUI-specific hooks. Use when working with MUI components, styling with sx prop, theme customization, or MUI utilities.
.claude/skills/davila7-mui/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 81% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 54% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 58% | 0% |
| case-15 | ✓→✗ | ▼ Worse | 114% | 0% |
| case-14 | ✓→✓ | = Same ✓ | 109% | 0% |
Material-UI v7 (released March 2025) patterns for component usage, styling with sx prop, theme integration, and responsive design.
Note: MUI v7 breaking changes from v6:
onBackdropClick removed from Modal - use onClose insteadslots and slotProps patternenableCssLayer config (works with Tailwind v4)typescriptimport { 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> ); }
For components with simple styling, define styles at the top:
typescriptimport 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> ); }
For complex components, create separate style file:
typescript// 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>; }
typescript// 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>
typescriptimport { Grid } from '@mui/material'; // 12-column grid <Grid container spacing={2}> <Grid item xs={12} md={6}> Left half </Grid> <Grid item xs={12} md={6}> Right half </Grid> </Grid> // Responsive grid <Grid container spacing={3}> <Grid item xs={12} sm={6} md={4} lg={3}> Card </Grid> {/* Repeat for more cards */} </Grid>
typescript<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>
typescript// 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>
typescriptimport { 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> ); }
typescript<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>
typescript// 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>
typescript<Typography sx={{ fontSize: { xs: '1rem', md: '1.5rem', lg: '2rem', }, lineHeight: { xs: 1.5, md: 1.75, }, }} > Responsive text </Typography>
typescriptimport { 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>
typescriptimport { 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>
typescriptimport { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material'; <Dialog open={open} onClose={handleClose}> <DialogTitle>Confirm Action</DialogTitle> <DialogContent> Are you sure you want to proceed? </DialogContent> <DialogActions> <Button onClick={handleClose}>Cancel</Button> <Button onClick={handleConfirm} variant="contained"> Confirm </Button> </DialogActions> </Dialog>
typescriptimport { 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>
typescriptimport { 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>; }
typescriptimport { 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>
typescriptimport 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 };
typescript// ✅ Good: Use theme tokens <Box sx={{ color: 'primary.main', p: 2 }} /> // ❌ Avoid: Hardcoded values <Box sx={{ color: '#1976d2', padding: '16px' }} />
typescript// ✅ Good: Use spacing scale <Box sx={{ p: 2, mb: 3, mt: 1 }} /> // ❌ Avoid: Random pixel values <Box sx={{ padding: '17px', marginBottom: '25px' }} />
For more detailed patterns, see:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-14 | pass→pass | 11,721 | 9,682 | -17% | 1 | 1 | 0% | 2,287 | 4,776 | +109% | 0 | 0 | — |
case-01 | fail→pass | 15,588 | 13,743 | -12% | 1 | 1 | 0% | 3,154 | 5,703 | +81% | 0 | 0 | — |
case-02 | fail→fail | 24,568 | 23,906 | -3% | 1 | 1 | 0% | 5,318 | 8,079 | +52% | 0 | 0 | — |
case-03 | pass→pass | 11,274 | 10,229 | -9% | 1 | 1 | 0% | 1,940 | 4,688 | +142% | 0 | 0 | — |
case-04 | pass→pass | 11,065 | 7,254 | -34% | 1 | 1 | 0% | 2,095 | 4,145 | +98% | 0 | 0 | — |
case-09 | pass→pass | 3,197 | 3,338 | +4% | 1 | 1 | 0% | 631 | 3,485 | +452% | 0 | 0 | — |
case-05 | pass→pass | 12,757 | 12,255 | -4% | 1 | 1 | 0% | 2,308 | 5,338 | +131% | 0 | 0 | — |
case-06 | pass→pass | 9,791 | 7,340 | -25% | 1 | 1 | 0% | 1,778 | 4,311 | +142% | 0 | 0 | — |
case-07 | pass→pass | 8,499 | 7,309 | -14% | 1 | 1 | 0% | 1,509 | 4,090 | +171% | 0 | 0 | — |
case-08 | fail→pass | 15,968 | 7,542 | -53% | 1 | 1 | 0% | 2,797 | 4,304 | +54% | 0 | 0 | — |
case-10 | pass→pass | 5,350 | 4,406 | -18% | 1 | 1 | 0% | 806 | 3,553 | +341% | 0 | 0 | — |
case-11 | pass→pass | 7,656 | 7,657 | +0% | 1 | 1 | 0% | 1,381 | 4,368 | +216% | 0 | 0 | — |
case-12 | pass→pass | 7,416 | 5,997 | -19% | 1 | 1 | 0% | 1,210 | 3,973 | +228% | 0 | 0 | — |
case-13 | pass→pass | 7,931 | 7,706 | -3% | 1 | 1 | 0% | 1,511 | 4,181 | +177% | 0 | 0 | — |
case-15 | pass→fail | 9,832 | 8,270 | -16% | 1 | 1 | 0% | 1,999 | 4,284 | +114% | 0 | 0 | — |
case-16 | fail→pass | 13,517 | 7,760 | -43% | 1 | 1 | 0% | 2,690 | 4,259 | +58% | 0 | 0 | — |
case-17 | pass→pass | 7,000 | 4,604 | -34% | 1 | 1 | 0% | 1,164 | 3,703 | +218% | 0 | 0 | — |
case-18 | pass→pass | 7,870 | 5,003 | -36% | 1 | 1 | 0% | 1,425 | 3,802 | +167% | 0 | 0 | — |
case-19 | pass→pass | 14,095 | 10,515 | -25% | 1 | 1 | 0% | 2,359 | 4,664 | +98% | 0 | 0 | — |
case-20 | pass→pass | 11,883 | 7,209 | -39% | 1 | 1 | 0% | 2,228 | 4,027 | +81% | 0 | 0 | — |
case-21 | pass→pass | 19,861 | 16,508 | -17% | 1 | 1 | 0% | 3,858 | 6,354 | +65% | 0 | 0 | — |
case-22 | pass→pass | 15,595 | 8,607 | -45% | 1 | 1 | 0% | 3,005 | 4,318 | +44% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.