All topics
Frontend · Learning hub

Material UI notes for developers

Master Material UI with a curated set of 3 developer notes — core concepts, patterns, and interview prep. Maintained by the DevRecall team.

Save this stack to your DevRecallMore Frontend notes
Material UI

Components & Theming

Material UI: Components & Theming Material UI (MUI) is the most popular React UI component library, implementing Google's Material Design. MUI v5+ uses Emotion

Material UI: Components & Theming

Material UI (MUI) is the most popular React UI component library, implementing Google's Material Design. MUI v5+ uses Emotion for styling and provides a powerful theme system.

Installation

npm install @mui/material @emotion/react @emotion/styled
# Icons (optional but commonly used)
npm install @mui/icons-material
# Date pickers
npm install @mui/x-date-pickers

Core Components

import Button from '@mui/material/Button'
import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box'
import Stack from '@mui/material/Stack'
import Paper from '@mui/material/Paper'
import Chip from '@mui/material/Chip'
import Avatar from '@mui/material/Avatar'
import CircularProgress from '@mui/material/CircularProgress'
import Tooltip from '@mui/material/Tooltip'
import IconButton from '@mui/material/IconButton'
import DeleteIcon from '@mui/icons-material/Delete'

// Button variants
<Button variant="contained" color="primary">Save</Button>
<Button variant="outlined" color="error" startIcon={<DeleteIcon />}>Delete</Button>
<Button variant="text" disabled>Disabled</Button>
<IconButton aria-label="delete"><DeleteIcon /></IconButton>

// Layout
<Stack direction="row" spacing={2} alignItems="center">
  <Avatar src="/avatar.png" alt="Alice" />
  <Typography variant="h6">Alice</Typography>
  <Chip label="Admin" color="primary" size="small" />
</Stack>

// Tooltip
<Tooltip title="Delete this item" placement="top">
  <IconButton><DeleteIcon /></IconButton>
</Tooltip>

Theme Setup

import { createTheme, ThemeProvider, CssBaseline } from '@mui/material'

const theme = createTheme({
  palette: {
    mode: 'light',  // or 'dark'
    primary: {
      main: '#1976d2',
      light: '#42a5f5',
      dark: '#1565c0',
    },
    secondary: {
      main: '#9c27b0',
    },
    background: {
      default: '#f5f5f5',
      paper: '#ffffff',
    },
  },
  typography: {
    fontFamily: '"Inter", "Roboto", sans-serif',
    h1: { fontSize: '2.5rem', fontWeight: 700 },
    body1: { fontSize: '1rem', lineHeight: 1.6 },
  },
  shape: {
    borderRadius: 8,
  },
  spacing: 8,  // base spacing unit in px (theme.spacing(2) = 16px)
})

// Wrap app
function App() {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />  {/* normalize CSS + apply background color */}
      <MyApp />
    </ThemeProvider>
  )
}

Dark Mode

const [mode, setMode] = useState<'light' | 'dark'>('light')

const theme = useMemo(() => createTheme({
  palette: { mode }
}), [mode])

// Toggle
<IconButton onClick={() => setMode(m => m === 'light' ? 'dark' : 'light')}>
  {mode === 'dark' ? <LightModeIcon /> : <DarkModeIcon />}
</IconButton>
Material UI

Form Controls, Data Display & Layout

Material UI: Forms, Data Display & Layout Form Components import TextField from '@mui/material/TextField' import Select from '@mui/material/Select' import MenuI

Material UI: Forms, Data Display & Layout

Form Components

import TextField from '@mui/material/TextField'
import Select from '@mui/material/Select'
import MenuItem from '@mui/material/MenuItem'
import FormControl from '@mui/material/FormControl'
import InputLabel from '@mui/material/InputLabel'
import FormHelperText from '@mui/material/FormHelperText'
import Checkbox from '@mui/material/Checkbox'
import FormControlLabel from '@mui/material/FormControlLabel'
import Switch from '@mui/material/Switch'
import Autocomplete from '@mui/material/Autocomplete'
import Slider from '@mui/material/Slider'

// TextField (most versatile input)
<TextField
  label="Email"
  type="email"
  variant="outlined"   // outlined | filled | standard
  error={!!errors.email}
  helperText={errors.email?.message}
  fullWidth
  required
  {...register('email')}
/>

// Select
<FormControl fullWidth>
  <InputLabel>Role</InputLabel>
  <Select value={role} label="Role" onChange={e => setRole(e.target.value)}>
    <MenuItem value="admin">Admin</MenuItem>
    <MenuItem value="user">User</MenuItem>
  </Select>
  <FormHelperText>Select user role</FormHelperText>
</FormControl>

// Autocomplete (combobox with search)
<Autocomplete
  options={countries}
  getOptionLabel={o => o.name}
  renderInput={params => <TextField {...params} label="Country" />}
  onChange={(_, value) => setCountry(value)}
  multiple   // allow multiple selections
/>

Data Display

import Table from '@mui/material/Table'
import TableBody from '@mui/material/TableBody'
import TableCell from '@mui/material/TableCell'
import TableHead from '@mui/material/TableHead'
import TableRow from '@mui/material/TableRow'
import TablePagination from '@mui/material/TablePagination'
import List from '@mui/material/List'
import ListItem from '@mui/material/ListItem'
import ListItemText from '@mui/material/ListItemText'
import ListItemAvatar from '@mui/material/ListItemAvatar'
import Alert from '@mui/material/Alert'
import Skeleton from '@mui/material/Skeleton'

// Table with pagination
<Table>
  <TableHead>
    <TableRow>
      <TableCell>Name</TableCell>
      <TableCell align="right">Actions</TableCell>
    </TableRow>
  </TableHead>
  <TableBody>
    {rows.map(row => (
      <TableRow key={row.id} hover>
        <TableCell>{row.name}</TableCell>
        <TableCell align="right">
          <IconButton size="small"><EditIcon /></IconButton>
        </TableCell>
      </TableRow>
    ))}
  </TableBody>
</Table>
<TablePagination
  count={total}
  page={page}
  rowsPerPage={25}
  onPageChange={(_, p) => setPage(p)}
/>

// Alert / Snackbar
<Alert severity="error" onClose={handleClose}>Something went wrong</Alert>
<Alert severity="success" variant="filled">Changes saved!</Alert>

// Loading skeleton
<Skeleton variant="text" width={200} />
<Skeleton variant="rectangular" height={120} />

Layout Components

import Grid from '@mui/material/Grid'
import Container from '@mui/material/Container'
import Drawer from '@mui/material/Drawer'
import AppBar from '@mui/material/AppBar'
import Toolbar from '@mui/material/Toolbar'
import Divider from '@mui/material/Divider'

// Responsive grid (Grid v2 — MUI v5.9+)
<Grid container spacing={2}>
  <Grid item xs={12} md={6} lg={4}>
    <Paper sx={{ p: 2 }}>Card 1</Paper>
  </Grid>
  <Grid item xs={12} md={6} lg={4}>
    <Paper sx={{ p: 2 }}>Card 2</Paper>
  </Grid>
</Grid>

// Container (max-width + center)
<Container maxWidth="lg">
  <Typography variant="h4">Page Title</Typography>
</Container>

// Sidebar Drawer
<Drawer open={open} onClose={() => setOpen(false)} anchor="left">
  <Box sx={{ width: 240 }} role="presentation">
    <List>...</List>
  </Box>
</Drawer>
Material UI

Customization: sx, styled & Theme Overrides

Material UI: Customization The sx Prop The sx prop is the primary way to apply one-off styles in MUI. It supports theme tokens, responsive values, and pseudo-cl

Material UI: Customization

The sx Prop

The sx prop is the primary way to apply one-off styles in MUI. It supports theme tokens, responsive values, and pseudo-classes.

// sx uses theme values: spacing, palette, breakpoints
<Box
  sx={{
    p: 2,              // padding: theme.spacing(2) = 16px
    mt: 'auto',        // marginTop: 'auto'
    bgcolor: 'primary.main',      // theme.palette.primary.main
    color: 'primary.contrastText',
    borderRadius: 2,   // theme.shape.borderRadius * 2
    boxShadow: 3,      // theme.shadows[3]

    // Responsive values
    width: { xs: '100%', md: '50%' },
    display: { xs: 'none', sm: 'block' },

    // Pseudo-classes
    '&:hover': { bgcolor: 'primary.dark' },
    '&.Mui-disabled': { opacity: 0.5 },

    // Nested selectors
    '& .MuiButton-root': { textTransform: 'none' },
  }}
>

styled() API

import { styled } from '@mui/material/styles'

// Create a reusable styled component
const StyledCard = styled(Paper)(({ theme }) => ({
  padding: theme.spacing(3),
  borderRadius: theme.shape.borderRadius * 2,
  transition: 'box-shadow 0.2s',
  '&:hover': {
    boxShadow: theme.shadows[8],
  },
}))

// With props
const ColoredChip = styled(Chip, {
  shouldForwardProp: prop => prop !== 'active',
})<{ active?: boolean }>(({ theme, active }) => ({
  backgroundColor: active ? theme.palette.success.main : theme.palette.grey[300],
  color: active ? theme.palette.success.contrastText : 'inherit',
}))

Theme Component Overrides

// Override default styles for ALL instances of a component globally
const theme = createTheme({
  components: {
    MuiButton: {
      defaultProps: {
        disableElevation: true,   // remove box-shadow from all contained buttons
        variant: 'contained',     // default variant
      },
      styleOverrides: {
        root: {
          textTransform: 'none',  // remove ALL_CAPS on all buttons
          borderRadius: 8,
        },
        containedPrimary: {
          '&:hover': { backgroundColor: '#1565c0' }
        }
      }
    },
    MuiTextField: {
      defaultProps: {
        size: 'small',
        variant: 'outlined',
      }
    },
    MuiCssBaseline: {
      styleOverrides: {
        body: { scrollbarWidth: 'thin' },  // global CSS
      }
    }
  }
})

useTheme & useMediaQuery

import { useTheme, useMediaQuery } from '@mui/material'

function MyComponent() {
  const theme = useTheme()
  const isMobile = useMediaQuery(theme.breakpoints.down('md'))

  return (
    <Box sx={{ flexDirection: isMobile ? 'column' : 'row' }}>
      <Typography color={theme.palette.primary.main}>
        Current spacing: {theme.spacing(2)}
      </Typography>
    </Box>
  )
}

MUI v5 vs v6 vs Tailwind

  • MUI v5: Emotion-based, sx prop, theme system — current mainstream choice

  • MUI v6: Pigment CSS (build-time CSS-in-JS, zero runtime) — better performance, more Next.js compatible

  • MUI vs Tailwind: MUI wins for rapid prototyping with rich components; Tailwind wins for custom design systems and smaller bundle size

  • shadcn/ui + Tailwind: growing alternative — copy-paste components with full ownership, no library dependency

  • Joy UI: MUI's alternative design system (not Material Design) — more modern aesthetic

Keep your Material UI knowledge sharp.

Save this stack to your personal DevRecall — add your own notes, track what you're learning, and share what you know with the community.

Get started — free forever