---
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 `