--- name: css-variables-pigment description: MUI CSS Variables mode (CssVarsProvider), Pigment CSS zero-runtime engine, and CSS custom properties theming triggers: - CSS variables - CssVarsProvider - Pigment CSS - zero-runtime - css custom properties - extendTheme - colorSchemes - getInitColorSchemeScript allowed-tools: - Read - Glob - Grep - Write - Edit globs: - "*.tsx" - "*.ts" - "theme*.ts" - "theme*.tsx" --- # MUI CSS Variables & Pigment CSS Skill ## 1. CssVarsProvider (MUI v6) `CssVarsProvider` replaces `ThemeProvider` when you want CSS-variable-based theming. Instead of injecting theme values into a JS context that triggers React re-renders on change, it emits CSS custom properties on the root element. Color scheme switches happen in CSS alone — no React tree re-render. ### Basic setup ```tsx import { CssVarsProvider, extendTheme } from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; const theme = extendTheme({ colorSchemes: { light: { palette: { primary: { main: '#1976d2' }, background: { default: '#fafafa' }, }, }, dark: { palette: { primary: { main: '#90caf9' }, background: { default: '#121212' }, }, }, }, }); function App() { return ( {/* your app */} ); } ``` ### Key differences from ThemeProvider | Feature | ThemeProvider + createTheme | CssVarsProvider + extendTheme | |---------|---------------------------|------------------------------| | Theme values in CSS | No (JS only) | Yes (CSS custom properties) | | Dark/light toggle | Re-renders entire tree | CSS-only, no re-render | | SSR flash prevention | Requires manual script | Built-in `getInitColorSchemeScript()` | | Theme access in sx/styled | `theme.palette.primary.main` | `theme.vars.palette.primary.main` or `var(--mui-palette-primary-main)` | | Multiple color schemes | Separate themes, context switch | Single theme object with `colorSchemes` | --- ## 2. extendTheme() vs createTheme() ### createTheme() Traditional API. Produces a theme object consumed by `ThemeProvider`. No CSS variables emitted. Good for projects that do not need CSS-variable-based theming or SSR flash prevention. ```tsx import { createTheme, ThemeProvider } from '@mui/material/styles'; const theme = createTheme({ palette: { mode: 'dark', primary: { main: '#90caf9' }, }, }); // Used with ``` ### extendTheme() Produces a CSS-variable-aware theme for `CssVarsProvider`. Accepts `colorSchemes` to define light and dark palettes in a single object. Automatically generates CSS custom properties. ```tsx import { extendTheme, CssVarsProvider } from '@mui/material/styles'; const theme = extendTheme({ cssVarPrefix: 'app', // default: 'mui' colorSchemes: { light: { palette: { primary: { main: '#1976d2' }, secondary: { main: '#9c27b0' }, }, }, dark: { palette: { primary: { main: '#90caf9' }, secondary: { main: '#ce93d8' }, }, }, }, typography: { fontFamily: '"Inter", "Roboto", "Helvetica", sans-serif', }, shape: { borderRadius: 12 }, }); // Used with ``` ### When to use which - **Use `extendTheme` + `CssVarsProvider`** when: - You need SSR without flash-of-wrong-theme - You want CSS-only dark mode toggling (no re-renders) - You embed MUI components in non-React contexts (CSS vars work everywhere) - You want to reference theme tokens in plain CSS files - You are on MUI v6+ - **Use `createTheme` + `ThemeProvider`** when: - Migrating from MUI v4/v5 and not ready to switch - Using third-party libraries that depend on `ThemeProvider` context - Your app has a single color scheme and does not need SSR --- ## 3. colorSchemes Configuration `colorSchemes` replaces the `palette.mode` approach. Define all schemes in one object: ```tsx const theme = extendTheme({ colorSchemes: { light: { palette: { primary: { main: '#1565c0', light: '#1976d2', dark: '#0d47a1' }, secondary: { main: '#7b1fa2' }, error: { main: '#d32f2f' }, warning: { main: '#ed6c02' }, info: { main: '#0288d1' }, success: { main: '#2e7d32' }, background: { default: '#ffffff', paper: '#f5f5f5' }, text: { primary: '#1a1a1a', secondary: '#666666' }, }, }, dark: { palette: { primary: { main: '#90caf9', light: '#bbdefb', dark: '#42a5f5' }, secondary: { main: '#ce93d8' }, error: { main: '#f44336' }, warning: { main: '#ffa726' }, info: { main: '#29b6f6' }, success: { main: '#66bb6a' }, background: { default: '#121212', paper: '#1e1e1e' }, text: { primary: '#ffffff', secondary: '#b0b0b0' }, }, }, }, }); ``` ### Custom color schemes beyond light/dark You can define additional schemes. The first key is treated as the default: ```tsx const theme = extendTheme({ colorSchemes: { light: { palette: { /* ... */ } }, dark: { palette: { /* ... */ } }, highContrast: { palette: { primary: { main: '#ffff00' }, background: { default: '#000000', paper: '#111111' }, text: { primary: '#ffffff' }, }, }, }, }); // Switch to it: const { setMode } = useColorScheme(); setMode('highContrast'); ``` ### Default color scheme ```tsx {/* Renders with dark scheme initially */} ``` Supported `defaultMode` values: `'light'`, `'dark'`, `'system'` (follows OS preference). --- ## 4. SSR Flash Prevention with getInitColorSchemeScript() Without this script, SSR apps show the default (light) theme briefly before hydration applies the user's preferred scheme. The script injects a blocking `