Material-UI Advanced Theming and Components

Updated 4 interview angles 6 min read source
On this page9
  1. Table of Contents
  2. Advanced Theming
  3. Component Customization
  4. Responsive Design
  5. Accessibility
  6. Best Practices
  7. Common Interview Questions
  8. Summary
  9. Interview angle

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

javascript
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

javascript
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

javascript
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

javascript
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

javascript
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

javascript
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

javascript
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

javascript
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

javascript
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

javascript
// 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

javascript
// 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

javascript
// 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 4

  • “How do you theme MUI beyond colours?” - the theme object carries palette, typography, spacing, breakpoints and components, where defaultProps and styleOverrides change every instance of a component. Overriding at the theme level is what keeps one-off sx props 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 createTheme and memoize any dynamic parts.