skills/material-ui-theming/AGENTS.md

10 KiB

Material UI theming and design tokens

Version 1.0.0 (Material UI v9)

Version notice: This skill targets Material UI v9 (>=9.0.0 <10.0.0). If you are using a different major version, verify the API details before following this guidance.

Note: This document is for agents and LLMs implementing themes and design tokens with Material UI. Grounded in docs/data/material/customization/ (theming, palette, dark-mode, css-theme-variables, typography, spacing, shape).


Abstract

A Material UI theme is a single object of design tokens (palette, typography, spacing, shape, breakpoints, etc.) plus optional per-component defaults (theme.components). Apps typically call createTheme once (or in composed steps), pass the result to ThemeProvider near the root, and read values with useTheme, sx, or styled. For system-driven light/dark, prefer colorSchemes and related APIs over a static palette.mode-only setup when you need toggling, tab sync, and SSR-friendly behavior; enable cssVariables when you want theme.vars, fewer theme nests for dark regions, and clearer debugging via --mui-* CSS variables.


Table of contents

  1. Core setup
  2. Where tokens live (design token map)
  3. Palette quick facts
  4. Color schemes vs palette-only dark
  5. CSS theme variables (cssVariables: true)
  6. Typography and spacing
  7. Composing and merging themes
  8. Nesting ThemeProvider
  9. Custom tokens (brand-specific design keys)
  10. Further reading

Core setup

  1. import { createTheme, ThemeProvider } from '@mui/material/styles' (Material UI default theme).
  2. Build a theme with createTheme({ ... }); wrap the app in <ThemeProvider theme={theme}> so descendants receive context.
  3. Use <CssBaseline /> inside the provider when you want baseline element styles and correct dark background behavior (see Dark mode).

Access in components: useTheme() from @mui/material/styles.


Where tokens live (design token map)

Area Role Doc
palette Semantic colors (primary, secondary, error, …), text, background, divider, action Palette
typography fontFamily, fontSize, variants (h1 through body2, button, …) Typography
spacing theme.spacing(n) scale (default 8px per unit) Spacing
shape borderRadius (default 4); optional extra radii need TypeScript augmentation Shape
breakpoints Responsive keys for sx / media queries Breakpoints
zIndex Layering tokens z-index
transitions Duration / easing helpers Transitions
components defaultProps, styleOverrides, variants per Mui* key Themed components

Full defaults: Default theme explorer.


Palette quick facts

  • Each palette color is usually main, light, dark, contrastText. Supplying main alone is often enough; createTheme can derive the rest.
  • Use @mui/material/colors (for example purple[500]) for Material Design hues when building a palette.
  • palette.mode: 'dark' forces a dark palette for the whole theme; if you use a fully custom palette with dark mode, ensure values match the mode (see Dark mode).

Color schemes vs palette-only dark

  • colorSchemes (for example colorSchemes: { dark: true }) enables built-in behavior: system preference, tab sync, optional transition disable on scheme change, storage, etc. Docs recommend it over the older, narrower palette-only approach for those features.
  • If both colorSchemes and palette are set, palette takes precedence. Avoid accidental overrides.
  • useColorScheme reads/updates mode for toggling. mode can be undefined on the first render; handle that to avoid hydration mismatches.
  • ThemeProvider supports storageManager, disableTransitionOnChange, noSsr, etc., for color-scheme UX and SSR (see Dark mode).

CSS theme variables (cssVariables: true)

  • Set cssVariables: true in createTheme so components use var(--mui-...) values. Prefer theme.vars in style callbacks when variables are enabled (mirrors palette/typography as CSS var references). See Usage.
  • Do not pass a custom vars key into createTheme. That key is reserved and autogenerated for this feature.
  • For dark-specific styles with CSS variables, use theme.applyStyles('dark', { ... }) rather than branching on theme.palette.mode in ways that cause flicker (see docs warning in Usage and Configuration).
  • InitColorSchemeScript: place before any rendered content to prevent the initial color-scheme flash. App Router: inside <body> before {children} in app/layout.tsx. Pages Router: in _document.tsx before <Main />. See Preventing SSR flickering.
  • Trade-offs: larger HTML (both schemes' variables), possible FCP impact; benefits include less JavaScript work on scheme switch and better SSR dark experience. See Overview.
  • CssVarsProvider is superseded by ThemeProvider with the same capabilities. Use ThemeProvider.

Typography and spacing

  • Typography uses rem; default root sizing is documented on Typography. Adjust typography.fontSize or per-variant sizes as needed; responsiveFontSizes(theme) can scale typography across breakpoints.
  • theme.spacing(k) follows the configured scale; sx spacing shorthands use the same system. Array-based spacing in the theme has limitations (negative / fractional / 'auto'). Prefer a function if you need full expressiveness (see Spacing).

Composing and merging themes

  • When one token should derive from another, build in steps: call createTheme with base options, then createTheme(theme, { ... }) using the first result (see Theming—Using theme options to define other options).
  • Avoid relying on multiple arguments to createTheme for merging; only the first argument is formally processed. Deep-merge yourself (for example deepmerge from @mui/utils) and pass a single object for forward compatibility (see Theming—createTheme(options, ...args)).

Nesting ThemeProvider

Inner provider overrides outer. Pass theme={(outer) => createTheme({ ...outer, ... })}-style functions only when intentionally extending the parent theme (see Theming—Nesting the theme).


Custom tokens (brand-specific design keys)

Add keys on the theme (for example status.danger) inside createTheme, then augment TypeScript with declare module '@mui/material/styles' on Theme and ThemeOptions (see Theming—Custom variables). For extra palette fields, follow Palette customization patterns.

Do not use theme.vars as a custom property name; it is private to CSS variables support.


Further reading

Topic Link
Theming overview & API Theming
Dark mode & toggling Dark mode
CSS variables overview CSS theme variables
Color tool / brand hues Color
TypeScript theme customization TypeScript—Customization of Theme

TypeScript snippet templates: reference.md.