Skip to content

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

Draft
silviuaavram wants to merge 41 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 41 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:

  • Create @mui/tailwind package.
  • Test the tailwind v4 import works in the docs.
    • The page is in docs/data/material/integrations/tailwindcss/tailwindcss-components.md.
    • It contains instructions on how to leverage mui states and palette via tailwind values.
    • No need for the postcss-import anymore, as it also broke the import from @mui/tailwind.
  • Change Slider and Toolbar to use css files instead of using styled arguments.
    • Toolbar also has custom breakpoints inside the css file, with variables that should be replaced at build.
  • Create a script to generate a components css file out of all component css files, buildCssArtifacts.mts
    • Generates 2 files, one with custom breakpoints replaced with MUI defaults, one with variables (as is).
    • If user does not need custom breakpoints, they should import @mui/material/components.css.
    • Otherwise, they should import components-source.css and use a transpiler to change the custom breakpoint variables with actual values. In our PoC, I used the vite.config directly, via resolveMuiCustomMedia.
  • Create @mui/styled-engine-noop and use it in non-emotion vite apps
  resolve: {
    alias: [
      {
        find: '@mui/styled-engine',
        replacement: path.resolve(MONOREPO_ROOT, 'packages/mui-styled-engine-noop/build'),
      },
    ],
  },
  • Instead of a runtime theme provider, we create a CSS file to act as a theme, based of CSS variables, at build time.
    • generateThemeCss takes the theme and generates the CSS based on the values in the theme object.
    • buildDefaultThemeCss.mts creates the actual css file, in @mui/material using the defaults, could be imported directly if user wants MUI theme.
    • buildThemeCss.mts is the consumer equivalent, that builds the same css file, but with the user's theme, check out the dedicated Vite app.
    • user will import the generated .css file in their app, along with the components .css file.
  • To achieve nested theming and portaled theming, we use ThemeScope to create a wrapping div element with a className and colorSchemeAttribute that are used by the theme to apply the nested values for the css variables.
    • It also uses ThemeScopeContext to pass className, colorSchemeAttribute and colorScheme to portal elements. In this PoC I'm using a ScopedDialog to show to the final version will look like in our portal components.
    • For the post-PoC, we should add the portal nested theme values to a div container that wraps all portal elements.
    • ThemeScope is decoupled from ThemeProvider receives the className, colorSchemeAttribute and colorScheme through a helper function getThemeScopeProps that ThemeProvider uses to get those props from the theme objects.
    • When using the static theme (css file), ThemeScope is used directly in the consumer code, as there is no more theme provider to apply behind the scenes.
    • It also needs to wrap the main app, since there is no provider to create the scope boundary.
  • Create 2 Vite apps for both ThemeProvider and static theme, as well as 2 experiments in the docs app (css + emotion)
    • Add useColorScheme support for both examples
      • create standalone hook for the static theme, since there is no context provider to supply it.
      • Implementation-wise, the color scheme logic in useColorScheme is now abstracted in useColorSchemeSetup.
    • For both examples, use sx, styleOverrides and style tag to change Slider.
    • In the static theme example, using sx will not do anything apart from showing a console warning.
    • In the static theme example, using styleOverrides on the theme object won't work, since there's no Emotion to parse them into styles.
    • Both apps have Toolbar imported, custom breakpoints override in the themes, so you can check the custom breakpoints.

Testing:

  • to check the standalone apps, which are better because we are using the package alias for style-noop in the case of CssThemeProvider, run pnpm -F @mui-internal/noop-vite-sandbox dev and pnpm -F @mui-internal/emotion-vite-sandbox dev. Check the links provided by the commands.
  • to check the bundle sizes for these apps (and make sure emotion is shaken out), run pnpm -F @mui-internal/emotion-vite-sandbox build and pnpm -F @mui-internal/noop-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