Claude
Skills
Sign in
Back

mui-theming

Included with Lifetime
$97 forever

MUI theming system — createTheme, palette, typography, dark mode, component overrides, TypeScript augmentation, and design tokens

Design

What this skill does


# MUI Theming Skill

## createTheme() API

The `createTheme` function is the entry point for all MUI customization. It accepts a deeply partial theme object and merges it with the defaults.

```tsx
import { createTheme } from '@mui/material/styles';

const theme = createTheme({
  palette: { ... },
  typography: { ... },
  spacing: 8,          // base spacing unit in px (default: 8)
  shape: { borderRadius: 8 },
  breakpoints: { ... },
  shadows: [...],
  transitions: { ... },
  zIndex: { ... },
});
```

---

## Palette

### Standard palette colors

```tsx
const theme = createTheme({
  palette: {
    primary: {
      light: '#757ce8',
      main: '#3f50b5',
      dark: '#002884',
      contrastText: '#fff',
    },
    secondary: {
      light: '#ff7961',
      main: '#f44336',
      dark: '#ba000d',
      contrastText: '#000',
    },
    error:   { main: '#d32f2f' },
    warning: { main: '#ed6c02' },
    info:    { main: '#0288d1' },
    success: { main: '#2e7d32' },
  },
});
```

MUI auto-generates `light`, `dark`, and `contrastText` from `main` if you omit them.

### Custom palette colors with augmentColor

```tsx
const theme = createTheme({
  palette: {
    // augmentColor adds light/dark/contrastText automatically
    neutral: theme.palette.augmentColor({
      color: { main: '#64748b' },
      name: 'neutral',
    }),
    brand: theme.palette.augmentColor({
      color: { main: '#6366f1', light: '#818cf8', dark: '#4f46e5' },
      name: 'brand',
    }),
  },
});
```

Use a two-step createTheme call when augmentColor needs the base theme:

```tsx
let theme = createTheme();
theme = createTheme(theme, {
  palette: {
    salmon: theme.palette.augmentColor({
      color: { main: '#FF5733' },
      name: 'salmon',
    }),
  },
});
```

### Background and text

```tsx
palette: {
  background: {
    default: '#f5f5f5',
    paper: '#ffffff',
  },
  text: {
    primary: 'rgba(0,0,0,0.87)',
    secondary: 'rgba(0,0,0,0.6)',
    disabled: 'rgba(0,0,0,0.38)',
  },
  divider: 'rgba(0,0,0,0.12)',
  action: {
    active: 'rgba(0,0,0,0.54)',
    hover: 'rgba(0,0,0,0.04)',
    selected: 'rgba(0,0,0,0.08)',
    disabled: 'rgba(0,0,0,0.26)',
    disabledBackground: 'rgba(0,0,0,0.12)',
    focus: 'rgba(0,0,0,0.12)',
  },
},
```

---

## Typography

```tsx
const theme = createTheme({
  typography: {
    fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif',
    fontSize: 14,             // base font size (rem calculation root)
    htmlFontSize: 16,         // <html> font size for rem calculations
    fontWeightLight: 300,
    fontWeightRegular: 400,
    fontWeightMedium: 500,
    fontWeightBold: 700,

    h1: { fontSize: '2.5rem', fontWeight: 700, lineHeight: 1.2, letterSpacing: '-0.01562em' },
    h2: { fontSize: '2rem',   fontWeight: 700, lineHeight: 1.3 },
    h3: { fontSize: '1.75rem', fontWeight: 600, lineHeight: 1.3 },
    h4: { fontSize: '1.5rem', fontWeight: 600, lineHeight: 1.4 },
    h5: { fontSize: '1.25rem', fontWeight: 600, lineHeight: 1.5 },
    h6: { fontSize: '1rem',   fontWeight: 600, lineHeight: 1.6 },

    subtitle1: { fontSize: '1rem',    fontWeight: 400, lineHeight: 1.75 },
    subtitle2: { fontSize: '0.875rem', fontWeight: 500, lineHeight: 1.57 },
    body1: { fontSize: '1rem',    fontWeight: 400, lineHeight: 1.5 },
    body2: { fontSize: '0.875rem', fontWeight: 400, lineHeight: 1.43 },
    button: { fontSize: '0.875rem', fontWeight: 600, textTransform: 'none' }, // disable ALL_CAPS
    caption: { fontSize: '0.75rem', fontWeight: 400, lineHeight: 1.66 },
    overline: { fontSize: '0.75rem', fontWeight: 400, textTransform: 'uppercase', letterSpacing: '0.08333em' },
  },
});
```

### Responsive typography

```tsx
typography: {
  h1: {
    fontSize: '2rem',
    [theme.breakpoints.up('md')]: { fontSize: '3rem' },
    [theme.breakpoints.up('lg')]: { fontSize: '4rem' },
  },
},
```

---

## Spacing

The spacing scale is factor-based. Default unit is 8px.

```tsx
const theme = createTheme({ spacing: 8 }); // default

theme.spacing(1)   // '8px'
theme.spacing(2)   // '16px'
theme.spacing(0.5) // '4px'
theme.spacing(1, 2)        // '8px 16px'
theme.spacing(1, 2, 3, 4)  // '8px 16px 24px 32px'

// Custom spacing function
const theme = createTheme({
  spacing: (factor: number) => `${0.25 * factor}rem`,
});
```

---

## Breakpoints

```tsx
const theme = createTheme({
  breakpoints: {
    values: {
      xs: 0,
      sm: 600,
      md: 900,
      lg: 1200,
      xl: 1536,
      // Add custom breakpoints:
      mobile: 0,
      tablet: 640,
      laptop: 1024,
      desktop: 1200,
    },
  },
});

// Usage in sx
<Box sx={{ fontSize: { xs: '1rem', md: '1.5rem', lg: '2rem' } }} />

// Usage in styles
theme.breakpoints.up('md')      // '@media (min-width:900px)'
theme.breakpoints.down('md')    // '@media (max-width:899.95px)'
theme.breakpoints.between('sm', 'md') // '@media (min-width:600px) and (max-width:899.95px)'
theme.breakpoints.only('md')    // '@media (min-width:900px) and (max-width:1199.95px)'
```

---

## Shape, Shadows, Transitions, zIndex

```tsx
const theme = createTheme({
  shape: {
    borderRadius: 8,  // default: 4
  },
  // shadows[0] = 'none', shadows[1-24] = elevation levels
  shadows: [
    'none',
    '0px 2px 1px -1px rgba(0,0,0,0.2),0px 1px 1px 0px rgba(0,0,0,0.14),0px 1px 3px 0px rgba(0,0,0,0.12)',
    // ... (24 levels total — override individual elevations selectively)
    ...Array(23).fill('none'),
  ],
  transitions: {
    duration: {
      shortest: 150,
      shorter: 200,
      short: 250,
      standard: 300,
      complex: 375,
      enteringScreen: 225,
      leavingScreen: 195,
    },
    easing: {
      easeInOut: 'cubic-bezier(0.4, 0, 0.2, 1)',
      easeOut: 'cubic-bezier(0.0, 0, 0.2, 1)',
      easeIn: 'cubic-bezier(0.4, 0, 1, 1)',
      sharp: 'cubic-bezier(0.4, 0, 0.6, 1)',
    },
  },
  zIndex: {
    mobileStepper: 1000,
    fab: 1050,
    speedDial: 1050,
    appBar: 1100,
    drawer: 1200,
    modal: 1300,
    snackbar: 1400,
    tooltip: 1500,
  },
});
```

---

## ThemeProvider and CssBaseline

```tsx
import { ThemeProvider, CssBaseline } from '@mui/material';
import { createTheme } from '@mui/material/styles';

const theme = createTheme({ ... });

function App() {
  return (
    <ThemeProvider theme={theme}>
      {/* CssBaseline normalizes browser styles and sets body background */}
      <CssBaseline />
      <YourApp />
    </ThemeProvider>
  );
}
```

---

## Dark Mode

### Static dark mode

```tsx
const darkTheme = createTheme({
  palette: {
    mode: 'dark',
    // MUI auto-adjusts all palette colors for dark mode
    // Override as needed:
    primary: { main: '#90caf9' },
    background: {
      default: '#121212',
      paper: '#1e1e1e',
    },
  },
});
```

### Dynamic dark mode with ColorModeContext

```tsx
import React, { createContext, useContext, useMemo, useState } from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';

// Create context
const ColorModeContext = createContext({ toggleColorMode: () => {} });

export function useColorMode() {
  return useContext(ColorModeContext);
}

export function ColorModeProvider({ children }: { children: React.ReactNode }) {
  const [mode, setMode] = useState<'light' | 'dark'>('light');

  const colorMode = useMemo(
    () => ({
      toggleColorMode: () =>
        setMode((prev) => (prev === 'light' ? 'dark' : 'light')),
    }),
    []
  );

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

  return (
    <ColorModeContext.Provider value={colorMode}>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        {children}
      </ThemeProvider>
    </ColorModeContext.Provider>
  );
}

// In a component:
function DarkModeToggle() {
  const { toggleColorMode } = useColorMode();
  return <IconButton onClick={toggleColorMode}><Brightness4Icon /></IconButton>;
}
```

### System preference detection

```tsx
impor
Files: 1
Size: 20.3 KB
Complexity: 28/100
Category: Design

Related in Design