Claude
Skills
Sign in
Back

css-variables-pigment

Included with Lifetime
$97 forever

MUI CSS Variables mode (CssVarsProvider), Pigment CSS zero-runtime engine, and CSS custom properties theming

Web Dev

What this skill does


# 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 (
    <CssVarsProvider theme={theme}>
      <CssBaseline enableColorScheme />
      {/* your app */}
    </CssVarsProvider>
  );
}
```

### 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 <ThemeProvider theme={theme}>
```

### 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 <CssVarsProvider theme={theme}>
```

### 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
<CssVarsProvider theme={theme} defaultMode="dark">
  {/* Renders with dark scheme initially */}
</CssVarsProvider>
```

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 `<script>` that reads `localStorage` (or OS preference) and sets the `data-*` attribute before first paint.

### Next.js App Router (layout.tsx)

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

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        {getInitColorSchemeScript({ defaultMode: 'system' })}
        {children}
      </body>
    </html>
  );
}
```

### Next.js Pages Router (_document.tsx)

```tsx
import { getInitColorSchemeScript } from '@mui/material/styles';
import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html lang="en">
      <Head />
      <body>
        {getInitColorSchemeScript({ defaultMode: 'system' })}
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}
```

### Configuration options

```tsx
getInitColorSchemeScript({
  defaultMode: 'system',              // 'light' | 'dark' | 'system'
  modeStorageKey: 'app-color-mode',   // localStorage key (default: 'mui-mode')
  colorSchemeStorageKey: 'app-scheme', // localStorage key for scheme
  attribute: 'data-app-color-scheme', // HTML attribute set on root element
  colorSchemeNode: 'html',            // DOM node to receive the attribute
});
```

---

## 5. Runtime Color Scheme Switching

### useColorScheme() hook

```tsx
import { useColorScheme } from '@mui/material/styles';
import Button from '@mui/material/Button';
import IconButton from '@mui/material/IconButton';
import DarkModeIcon from '@mui/icons-material/DarkMode';
import LightModeIcon from '@mui/icons-material/LightMode';
import SettingsBrightnessIcon from '@mui/icons-material/SettingsBrightness';

function ThemeToggle() {
  const { mode, setMode } = useColorScheme();

  if (!mode) return null; // avoids SSR hydration mismatch

  return (
    <Button
      onClick={() => setMode(mode === 'dark' ? 'light' : 'dark')}
      startIcon={mode === 'dark' ? <LightModeIcon /> : <DarkModeIcon />}
    >
      {mode === 'dark' ? 'Light mode' : 'Dark mode'}
    </Button>
  );
}
```

### Three-way toggle (light / dark / system)

```tsx
function ThemeSwitcher() {
  const { mode, setMode } = useColorScheme();

  if (!mode) return null;

  const options = [
    { value: 'light', icon: <LightModeIcon />, label: 'Light' },
    { value: 'dark', icon: <DarkModeIcon />, label: 'Dark' },
    { value: 'system

Related in Web Dev