Material-UI Advanced Theming and Components
This guide covers advanced theming techniques, component customization, and best practices for Material-UI applications.
Table of Contents
Advanced Theming
Theme Structure
import { createTheme } from '@mui/material/styles';
const theme = createTheme({
palette: {
mode: 'light', // or 'dark'
primary: {
main: '#1976d2',
light: '#42a5f5',
dark: '#1565c0',
contrastText: '#fff',
},
secondary: {
main: '#dc004e',
light: '#ff5983',
dark: '#9a0036',
contrastText: '#fff',
},
background: {
default: '#fafafa',
paper: '#fff',
},
text: {
primary: 'rgba(0, 0, 0, 0.87)',
secondary: 'rgba(0, 0, 0, 0.6)',
},
},
typography: {
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
h1: {
fontSize: '2.5rem',
fontWeight: 500,
lineHeight: 1.2,
},
h2: {
fontSize: '2rem',
fontWeight: 500,
lineHeight: 1.3,
},
body1: {
fontSize: '1rem',
lineHeight: 1.5,
},
button: {
textTransform: 'none',
fontWeight: 500,
},
},
shape: {
borderRadius: 8,
},
spacing: 8,
breakpoints: {
values: {
xs: 0,
sm: 600,
md: 900,
lg: 1200,
xl: 1536,
},
},
components: {
MuiButton: {
styleOverrides: {
root: {
borderRadius: 8,
textTransform: 'none',
},
contained: {
boxShadow: 'none',
'&:hover': {
boxShadow: '0px 2px 4px rgba(0,0,0,0.2)',
},
},
},
variants: [
{
props: { variant: 'gradient' },
style: {
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
color: 'white',
},
},
],
},
MuiCard: {
styleOverrides: {
root: {
boxShadow: '0px 2px 8px rgba(0,0,0,0.1)',
},
},
},
},
});
Dark Mode Theme
import { createTheme, ThemeProvider } from '@mui/material/styles';
import { useState } from 'react';
function App() {
const [mode, setMode] = useState('light');
const theme = createTheme({
palette: {
mode,
...(mode === 'light'
? {
// Light mode colors
primary: {
main: '#1976d2',
},
background: {
default: '#fafafa',
paper: '#fff',
},
}
: {
// Dark mode colors
primary: {
main: '#90caf9',
},
background: {
default: '#121212',
paper: '#1e1e1e',
},
}),
},
});
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Button onClick={() => setMode(mode === 'light' ? 'dark' : 'light')}>
Toggle {mode === 'light' ? 'Dark' : 'Light'} Mode
</Button>
<YourApp />
</ThemeProvider>
);
}
Custom Color Palette
const theme = createTheme({
palette: {
primary: {
50: '#e3f2fd',
100: '#bbdefb',
200: '#90caf9',
300: '#64b5f6',
400: '#42a5f5',
500: '#2196f3',
600: '#1e88e5',
700: '#1976d2',
800: '#1565c0',
900: '#0d47a1',
A100: '#82b1ff',
A200: '#448aff',
A400: '#2979ff',
A700: '#2962ff',
},
custom: {
main: '#ff6b6b',
light: '#ff8e8e',
dark: '#e55a5a',
},
},
});
Component Customization
Styled Components
import { styled } from '@mui/material/styles';
import { Button, Card } from '@mui/material';
const CustomButton = styled(Button)(({ theme }) => ({
background: `linear-gradient(45deg, ${theme.palette.primary.main} 30%, ${theme.palette.secondary.main} 90%)`,
border: 0,
borderRadius: 15,
boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
color: 'white',
height: 48,
padding: '0 30px',
'&:hover': {
background: `linear-gradient(45deg, ${theme.palette.primary.dark} 30%, ${theme.palette.secondary.dark} 90%)`,
},
}));
const CustomCard = styled(Card)(({ theme }) => ({
position: 'relative',
backgroundColor: theme.palette.grey[800],
color: theme.palette.common.white,
marginBottom: theme.spacing(4),
backgroundImage: 'url(https://source.unsplash.com/random)',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
'&::before': {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0,0,0,.3)',
content: '""',
},
}));
Sx Prop Examples
import { Box, Button } from '@mui/material';
function SxExamples() {
return (
<Box
sx={{
display: 'flex',
flexDirection: 'column',
gap: 2,
p: 3,
bgcolor: 'background.paper',
borderRadius: 2,
boxShadow: 1,
'&:hover': {
boxShadow: 3,
},
'@media (min-width: 600px)': {
flexDirection: 'row',
},
}}
>
<Button
sx={{
bgcolor: 'primary.main',
color: 'white',
'&:hover': {
bgcolor: 'primary.dark',
},
'&.Mui-disabled': {
bgcolor: 'grey.300',
},
}}
>
Custom Button
</Button>
</Box>
);
}
Responsive Design
Responsive Grid
import { Grid, Paper } from '@mui/material';
function ResponsiveGrid() {
return (
<Grid container spacing={3}>
<Grid item xs={12} sm={6} md={4} lg={3}>
<Paper sx={{ p: 2, textAlign: 'center' }}>
xs=12 sm=6 md=4 lg=3
</Paper>
</Grid>
<Grid item xs={12} sm={6} md={4} lg={3}>
<Paper sx={{ p: 2, textAlign: 'center' }}>
xs=12 sm=6 md=4 lg=3
</Paper>
</Grid>
<Grid item xs={12} sm={6} md={4} lg={3}>
<Paper sx={{ p: 2, textAlign: 'center' }}>
xs=12 sm=6 md=4 lg=3
</Paper>
</Grid>
<Grid item xs={12} sm={6} md={4} lg={3}>
<Paper sx={{ p: 2, textAlign: 'center' }}>
xs=12 sm=6 md=4 lg=3
</Paper>
</Grid>
</Grid>
);
}
Responsive Typography
import { Typography, Box } from '@mui/material';
function ResponsiveTypography() {
return (
<Box>
<Typography
variant="h1"
sx={{
fontSize: {
xs: '2rem',
sm: '3rem',
md: '4rem',
lg: '5rem',
},
}}
>
Responsive Heading
</Typography>
<Typography
sx={{
fontSize: {
xs: '0.875rem',
sm: '1rem',
md: '1.125rem',
},
lineHeight: {
xs: 1.4,
sm: 1.5,
md: 1.6,
},
}}
>
Responsive body text
</Typography>
</Box>
);
}
Accessibility
ARIA Support
import { Button, TextField, Alert } from '@mui/material';
function AccessibleComponents() {
return (
<div>
<TextField
label="Email"
type="email"
aria-describedby="email-helper"
helperText="Enter your email address"
required
inputProps={{
'aria-label': 'Email address input',
}}
/>
<Button
aria-label="Submit form"
aria-describedby="submit-description"
>
Submit
</Button>
<Alert
severity="info"
aria-live="polite"
role="alert"
>
This is an informational message
</Alert>
</div>
);
}
Focus Management
import { Button, Dialog, DialogTitle, DialogContent } from '@mui/material';
import { useRef } from 'react';
function FocusManagement() {
const buttonRef = useRef(null);
return (
<div>
<Button ref={buttonRef}>
Open Dialog
</Button>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="dialog-title"
aria-describedby="dialog-description"
>
<DialogTitle id="dialog-title">
Dialog Title
</DialogTitle>
<DialogContent>
Dialog content
</DialogContent>
</Dialog>
</div>
);
}
Best Practices
1. Component Composition
// Good: Compose components
function UserCard({ user }) {
return (
<Card>
<CardContent>
<Box display="flex" alignItems="center" gap={2}>
<Avatar src={user.avatar} />
<Box>
<Typography variant="h6">{user.name}</Typography>
<Typography variant="body2" color="text.secondary">
{user.email}
</Typography>
</Box>
</Box>
</CardContent>
</Card>
);
}
2. Theme Consistency
// Use theme values consistently
const theme = createTheme({
palette: {
primary: {
main: '#1976d2',
},
},
typography: {
h1: {
fontSize: '2.5rem',
fontWeight: 500,
},
},
spacing: 8,
});
// Use theme.spacing() for consistent spacing
<Box sx={{ p: theme.spacing(2), m: theme.spacing(1) }}>
Content
</Box>
3. Performance Optimization
// Use React.memo for expensive components
const ExpensiveComponent = React.memo(({ data }) => {
return (
<List>
{data.map(item => (
<ListItem key={item.id}>
{item.name}
</ListItem>
))}
</List>
);
});
// Use useMemo for expensive calculations
const expensiveValue = useMemo(() => {
return computeExpensiveValue(data);
}, [data]);
Common Interview Questions
Q: How do you customize Material-UI components?
- Through theme customization, styled components, sx prop, or component styleOverrides
Q: What’s the difference between sx prop and styled components?
- sx prop is for one-off styling, styled components are for reusable styled components
Q: How do you implement dark mode in Material-UI?
- Create a theme with mode: ‘dark’ and use ThemeProvider to wrap your app
Q: How do you handle responsive design in Material-UI?
- Using the Grid system with breakpoint props and responsive values in sx prop
Q: What are the accessibility features in Material-UI?
- Built-in ARIA attributes, keyboard navigation, screen reader support, and WCAG compliance
Q: How do you optimize Material-UI performance?
- Use React.memo, useMemo, and avoid unnecessary re-renders
Summary
- Material-UI provides a comprehensive component library with consistent APIs
- Advanced theming system allows for deep customization
- Built-in accessibility features ensure inclusive design
- Responsive design is handled through Grid system and responsive values
- Performance optimization techniques help maintain smooth user experience
- Best practices ensure maintainable and scalable code
Interview angle
- “How do you theme MUI beyond colours?” - the theme object carries palette, typography, spacing, breakpoints and
components, wheredefaultPropsandstyleOverrideschange every instance of a component. Overriding at the theme level is what keeps one-offsxprops from spreading through the codebase. - “How do you support dark mode without a flash?” - the CSS-variables theme, which emits custom properties and switches with a data attribute rather than re-rendering a new theme object. That also makes SSR work without a hydration mismatch.
- “How do you extend the theme in TypeScript?” - module augmentation on MUI’s theme interfaces, so custom palette keys and variants type-check. Without it, custom keys are a runtime-only convention.
- “What is the performance concern?” - creating the theme inside a component recreates it every render and invalidates the whole styling cache. Build it once at module level with
createThemeand memoize any dynamic parts.