Skip to content

[POC] Use a static build-time generated CSS file as theme#48745

Draft
silviuaavram wants to merge 43 commits into
mui:masterfrom
silviuaavram:poc/css-static-theme-provider
Draft

[POC] Use a static build-time generated CSS file as theme#48745
silviuaavram wants to merge 43 commits into
mui:masterfrom
silviuaavram:poc/css-static-theme-provider

Conversation

@silviuaavram

@silviuaavram silviuaavram commented Jun 30, 2026

Copy link
Copy Markdown
Member

Spinoff from #48652. Instead of using CSSThemeProvider, we remove the runtime part entirely, and use CSS generated at build time, with CSS variables, to act as a theme. The changes below are partially the ones from the runtime provider PR.

Changes:

Summary

Component CSS

  • Move the base styles for Slider and Toolbar from styled() arguments to CSS Modules.
    • Keep the styled() slot shells so Emotion users retain sx, styled(), and styleOverrides.
    • Use :global(.Mui*) selectors to preserve MUI's public class names without CSS Module hashes.
    • Author Toolbar media queries with aliases such as @media (--mui-breakpoint-up-sm).

CSS Delivery

Provide two mutually exclusive component CSS paths:

  1. Default breakpoints:

    • buildCssArtifacts.mts combines component CSS Modules into @mui/material/styles.css.
    • Lightning CSS resolves custom-media aliases using MUI's default breakpoints.
    • Consumers import @mui/material/styles.css once.
    • This path includes all migrated component CSS and does not tree-shake styles.
  2. Custom breakpoints:

    • buildCssModulesVariant.mts generates a parallel @mui/material/css-modules/* package tree.
    • Components in this tree import their corresponding CSS Modules.
    • CSS follows component imports and can be tree-shaken.
    • Consumers configure PostCSS or Lightning CSS to resolve the aliases from their theme.
    • Consumers must not also import @mui/material/styles.css, as that would duplicate styles.

CSS Build Tools

  • Add @mui/material-css-tools for build-time CSS integration.
  • Provide muiMaterialCssModules() to select the parallel package in Vite.
  • Provide muiCustomMedia({ theme }) adapters for Vite/Lightning CSS and PostCSS.
  • Provide generateBreakpointCustomMedia() and
    getBreakpointCustomMediaDefinitions() for custom bundler integrations.
  • The same adapters also allow application CSS to use aliases such as
    @media (--mui-breakpoint-up-tablet).
  • Breakpoints are compiled once for the whole CSS build. Nested themes cannot use different
    breakpoint values.

Static Theme Generation

  • Add generateThemeCss() to serialize a CSS-variable theme into static CSS.
  • buildDefaultThemeCss.mts generates @mui/material/default-theme.css.
  • Consumer build scripts can generate their own theme.css from theme options.
  • Consumers import the generated theme CSS together with one component CSS path:
    • @mui/material/styles.css for default breakpoints, or
    • the CSS Modules package variant for custom breakpoints.
  • Component styleOverrides are not serialized into the static theme.
  • sx is ignored by the noop styling engine and emits a development warning.

Theme Scoping

  • Add ThemeScope as the DOM boundary for root and nested CSS-variable themes.
  • Runtime ThemeProvider uses getThemeScopeProps() to derive a scope from simple class-based
    rootSelector values.
  • Static-theme consumers render ThemeScope directly for both root and nested themes.
  • ThemeScopeContext exposes the active class, color scheme, and color-scheme attribute.
  • useThemeScopeProps() copies that scope onto portal roots.
  • The PoC ScopedDialog passes these props through slotProps.root.
  • A production implementation should integrate portal scoping into Modal or a shared portal
    container rather than requiring a consumer wrapper.

Color Scheme

  • Extract the shared color-scheme state logic into useColorSchemeSetup.
  • Runtime ThemeProvider continues exposing its context-backed useColorScheme.
  • Static themes use the standalone @mui/material/colorScheme hook.
  • Production SSR should also cover initial color-scheme setup before hydration to prevent a
    first-paint mismatch.

Tailwind

  • Add @mui/tailwind with Tailwind v3 preset/plugin and Tailwind v4 CSS integration.
  • Move theme-specific generation helpers to @mui/material-css-tools:
    • createTailwindPreset(theme) for Tailwind v3.
    • generateTailwindThemeCss(theme) for Tailwind v4.
  • Generated Tailwind tokens reference MUI CSS variables, so palette tokens follow nested themes.
  • Tailwind breakpoints are generated from the same build-time theme as component CSS.
  • The docs import @mui/tailwind/v4.css directly without postcss-import.

Sandboxes

  • emotion-vite-sandbox: Emotion, runtime ThemeProvider, CSS Modules, PostCSS, custom
    sm=720px, and Tailwind v3.
  • noop-vite-sandbox: static generated theme, noop engine, CSS Modules, Lightning CSS, custom
    sm=720px, and Tailwind v4.
  • noop-default-css-vite-sandbox: static generated theme, noop engine, aggregate
    @mui/material/styles.css, default sm=600px, and Tailwind v4.
  • All three exercise Toolbar, Slider, nested themes, portal scoping, plain CSS overrides,
    color-scheme switching, and Tailwind tokens.

Verification

pnpm -F @mui/material build
pnpm -F @mui/material-css-tools build
pnpm -F @mui-internal/emotion-vite-sandbox dev
pnpm -F @mui-internal/noop-vite-sandbox dev
pnpm -F @mui-internal/noop-default-css-vite-sandbox dev

pnpm -F @mui-internal/emotion-vite-sandbox build
pnpm -F @mui-internal/noop-vite-sandbox build
pnpm -F @mui-internal/noop-default-css-vite-sandbox build

@code-infra-dashboard

code-infra-dashboard Bot commented Jun 30, 2026

Copy link
Copy Markdown

Deploy preview

Bundle size

Bundle Parsed size Gzip size
@mui/material 🔺+1.89KB(+0.36%) 🔺+875B(+0.58%)
@mui/lab 🔺+44B(+0.13%) 🔺+12B(+0.14%)
@mui/private-theming 0B(0.00%) 0B(0.00%)
@mui/system 🔺+1.51KB(+2.17%) 🔺+429B(+1.75%)
@mui/utils 🔺+42B(+0.27%) 🔺+13B(+0.22%)

Details of bundle changes


Check out the code infra dashboard for more information about this PR.

@silviuaavram silviuaavram added the scope: system The system, the design tokens / styling foundations used across components. eg. @mui/system with MUI label Jun 30, 2026
@silviuaavram silviuaavram self-assigned this Jun 30, 2026
@github-actions github-actions Bot added the PR: out-of-date The pull request has merge conflicts and can't be merged. label Jul 3, 2026
@github-actions github-actions Bot added PR: out-of-date The pull request has merge conflicts and can't be merged. and removed PR: out-of-date The pull request has merge conflicts and can't be merged. labels Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR: out-of-date The pull request has merge conflicts and can't be merged. scope: system The system, the design tokens / styling foundations used across components. eg. @mui/system with MUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant