Material UI
03 / 03

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-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 own version of these notes — editable, searchable, and organised by your stack.

Start free