Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
144 commits
Select commit Hold shift + click to select a range
8bb81bc
[poc] Use noop package for styling purposes
mnajdova Nov 13, 2024
d909c66
[poc] Use noop package for styling purposes
mnajdova Nov 13, 2024
b304f1c
revert system changes
mnajdova Nov 14, 2024
c36cdc9
convert to ts
mnajdova Nov 14, 2024
9102b08
prettier & copy module.css in built output
mnajdova Nov 14, 2024
25ed058
add theme and sx css layer
siriwatknp Apr 25, 2025
650c5be
add experimental_dedicatedCssLayer option
siriwatknp Apr 25, 2025
072a318
fix nested rules
siriwatknp Apr 25, 2025
4663f11
wip
siriwatknp Apr 25, 2025
fd97877
wip
siriwatknp Apr 28, 2025
f5560be
Merge branch 'master' of https://github.com/mui/material-ui into feat…
siriwatknp May 7, 2025
32ab754
restore non-working approach
siriwatknp May 7, 2025
ddd1bdb
poc nested css layers
siriwatknp May 8, 2025
222fc84
Merge branch 'master' into feat/mui-css-layer
siriwatknp May 8, 2025
aaf9ac7
prevent recursive nesting
siriwatknp May 9, 2025
1d2011a
rename to experimental_modularCssLayers
siriwatknp May 9, 2025
1955562
Merge branch 'feat/mui-css-layer' of github.com:siriwatknp/material-u…
siriwatknp May 9, 2025
837d9f6
add layer `custom` and rename `base` to `default`
siriwatknp May 9, 2025
ae48dd6
revert unnecessary
siriwatknp May 9, 2025
c6ac569
remove experiment
siriwatknp May 9, 2025
63926d7
Merge branch 'master' of https://github.com/mui/material-ui into feat…
siriwatknp May 9, 2025
ce9d9c0
Merge branch 'master' of https://github.com/mui/material-ui into feat…
siriwatknp May 13, 2025
8395602
revert
siriwatknp May 15, 2025
48699bd
Merge branch 'master' of https://github.com/mui/material-ui into feat…
siriwatknp May 15, 2025
7722bca
add comment
siriwatknp May 15, 2025
a4f2db9
add test
siriwatknp May 15, 2025
9ea768d
update test
siriwatknp May 15, 2025
92d1e0e
add global layer to global styles
siriwatknp May 20, 2025
6843a52
Merge branch 'master' of https://github.com/mui/material-ui into feat…
siriwatknp May 20, 2025
748f822
update docs layer config
siriwatknp May 20, 2025
e1161fb
skip nested layer for non serialized
siriwatknp May 20, 2025
7cb2bd4
add name to all components
siriwatknp May 20, 2025
94ebdec
use Regex
siriwatknp May 20, 2025
439be03
fix processed resolvedStyled
siriwatknp May 20, 2025
45214e7
add documentation
siriwatknp May 20, 2025
3e5476d
add shrink to show placeholder
siriwatknp May 20, 2025
bb4df19
update demo
siriwatknp May 20, 2025
af27dba
update docs
siriwatknp May 20, 2025
5b1bebe
enable css layer to regression
siriwatknp May 20, 2025
74a320e
run docs:i18n
siriwatknp May 20, 2025
2d636e7
fix test
siriwatknp May 20, 2025
667a305
include Joy regression
siriwatknp May 20, 2025
f232388
remove variants suffix
siriwatknp May 21, 2025
355789e
add layer order to regression and update docs
siriwatknp May 21, 2025
41b29dc
fix demo to combine styles
siriwatknp May 22, 2025
9cea871
fix missing name and default layer check
siriwatknp May 22, 2025
9216be0
fix global styles function in array
siriwatknp May 22, 2025
d940d03
fix matching joy demos
siriwatknp May 22, 2025
4d612c8
attach layer to the top
siriwatknp May 22, 2025
49b5247
remove styledEngineProvider
siriwatknp May 22, 2025
9a635ef
fix template theme
siriwatknp May 22, 2025
91b64a1
update test viewer
siriwatknp May 22, 2025
c30a498
slot should be default layer
siriwatknp May 22, 2025
d7b8b7b
fix checkout template
siriwatknp May 22, 2025
9d3c64b
fix CustomizedSelect
siriwatknp May 22, 2025
3dd3d6d
move material icons to css file
siriwatknp May 22, 2025
870feb2
add Mui name to use default layer
siriwatknp May 22, 2025
1d9e21c
fix dashboard
siriwatknp May 22, 2025
95053b2
Merge branch 'master' of https://github.com/mui/material-ui into feat…
siriwatknp Jun 2, 2025
7f4e9ab
update docs
siriwatknp Jun 2, 2025
d6c44c1
docs:i18n
siriwatknp Jun 2, 2025
b763222
Merge branch 'master' of https://github.com/mui/material-ui into feat…
siriwatknp Jun 3, 2025
e74ab11
enable modularCssLayers in templates
siriwatknp Jun 3, 2025
fbe0862
fix global styles to not skip layer order
siriwatknp Jun 3, 2025
e290558
fix templates
siriwatknp Jun 3, 2025
f155b6d
add useLayerOrder
siriwatknp Jun 3, 2025
62eed49
remove style injection logic
siriwatknp Jun 3, 2025
e0f3507
update docs
siriwatknp Jun 3, 2025
b8842b3
revert files related to docs
siriwatknp Jun 3, 2025
7767589
fix useLayerOrder and add test
siriwatknp Jun 4, 2025
d7acd50
fix test
siriwatknp Jun 4, 2025
c834367
update demo
siriwatknp Jun 4, 2025
4a8e2ba
update docs
siriwatknp Jun 4, 2025
93dfe4a
remove unncessary `skipVariantsResolver`
siriwatknp Jun 4, 2025
89f905c
revert Demo.js
siriwatknp Jun 4, 2025
71f8869
Merge branch 'master' into poc/styling-v8
mnajdova Jun 4, 2025
48a27ba
updates after merge
mnajdova Jun 4, 2025
9c595cd
lockfile
mnajdova Jun 4, 2025
59ffb75
add layer
mnajdova Jun 4, 2025
a5f2218
use different layer
mnajdova Jun 4, 2025
bb42fe2
Update packages/mui-system/src/styleFunctionSx/styleFunctionSx.test.js
siriwatknp Jun 5, 2025
70fe7bf
Merge branch 'feat/mui-css-layer' into poc/styling-v8
mnajdova Jun 5, 2025
58f5c2e
change the layer name
mnajdova Jun 5, 2025
3232ade
Slider draft
mnajdova Jun 6, 2025
5d51120
export Emotion Slider
mnajdova Jun 6, 2025
fc8a88e
include regular CSS files, not just CSS modules
mnajdova Jun 6, 2025
fee13d7
use logical CSS properties
mnajdova Jun 7, 2025
e76dc3d
Merge branch 'master' into poc/styling-v8
mnajdova Apr 24, 2026
cc38b5a
prettier
mnajdova Apr 24, 2026
826a8b8
fixes
mnajdova Apr 24, 2026
b797bcf
use latest slider version
mnajdova Apr 24, 2026
33c5234
Support shouldForwardProp
mnajdova Apr 24, 2026
aceeef4
Add warning if using sx prop
mnajdova Apr 24, 2026
8db9692
Refactor Header to use global CSS
mnajdova Apr 24, 2026
2de2e47
@mui/tailwind
mnajdova Apr 28, 2026
ccb23e2
experiments
mnajdova Apr 29, 2026
9223497
fixes
mnajdova Apr 29, 2026
79bb37d
docs:typescript:formatted
mnajdova Apr 29, 2026
79a9df8
build script & lint issues
mnajdova Apr 29, 2026
44ac7f9
build package
mnajdova Apr 29, 2026
91adb11
fixes
mnajdova Apr 29, 2026
83f8b99
more CI fixes
mnajdova Apr 29, 2026
7694081
Merge branch 'master' into poc/styling-v8
mnajdova Apr 29, 2026
780ebdc
pnpm-lock
mnajdova Apr 29, 2026
a75d052
CI fixes
mnajdova Apr 29, 2026
c875b5c
CI fixes
mnajdova Apr 30, 2026
c85404f
prettier
mnajdova Apr 30, 2026
b9fb99b
some visual fixes
mnajdova May 1, 2026
614149c
thumb fix
mnajdova May 1, 2026
63b6e66
fully support RTL in Slider
silviuaavram May 14, 2026
e87d2d3
CssVarsInjector and styleSheetsToString
silviuaavram May 15, 2026
97c3cd2
use theme provider in tw pg
silviuaavram May 15, 2026
d16119e
support dark mode in experiments
silviuaavram May 15, 2026
839ca6c
guard against null
silviuaavram May 18, 2026
9dc7f35
guard against no generateStyleSheets
silviuaavram May 18, 2026
389d9a8
prettier
silviuaavram May 18, 2026
2ad4dc1
add CssVarsInjector to the skipComponent regex
silviuaavram May 18, 2026
a44b0ff
fix reexport of styleSheetsToString
silviuaavram May 18, 2026
df56225
make css vars injector accept document and var prefix
silviuaavram May 18, 2026
03031d2
Merge branch 'master' into poc/styling-v8
silviuaavram May 18, 2026
d530174
dedupe
silviuaavram May 18, 2026
d10913f
add defaults to style transitions in slider
silviuaavram May 20, 2026
4b5046e
create css theme provider and experiement
silviuaavram May 20, 2026
846369e
remove emotion from useThemeWithoutDefault
silviuaavram May 20, 2026
16e9181
fix emotion playground text color
silviuaavram May 20, 2026
4df4739
remove anim defaults and PrivateThemeProvider
silviuaavram May 21, 2026
b3734b2
mark ToDos
silviuaavram May 22, 2026
1d859c6
fix some tests
silviuaavram May 22, 2026
46b4cba
generate transforms variables
silviuaavram May 25, 2026
30954b1
add another todo
silviuaavram May 25, 2026
c870140
fix tailwind experiment
silviuaavram May 26, 2026
ea94c6e
remove some comments
silviuaavram May 27, 2026
3ec2bcd
test out the css file approach
silviuaavram May 27, 2026
6c81ab1
export the default theme
silviuaavram Jun 1, 2026
f363e9f
create 2 slider experiments
silviuaavram Jun 1, 2026
00f2121
add todo file and default theme fix
silviuaavram Jun 4, 2026
6cf9beb
update slider style
silviuaavram Jun 5, 2026
62e0216
improved todo file
silviuaavram Jun 5, 2026
00d1b13
add vite app without emotion
silviuaavram Jun 5, 2026
141ee37
refresh todo list
silviuaavram Jun 6, 2026
5e4aa4d
remove slider override
silviuaavram Jun 8, 2026
2cfcabb
improved todolist
silviuaavram Jun 8, 2026
f54156d
remove sx from static theme
silviuaavram Jun 8, 2026
0e5c8b2
add 2 apps for emotion + mantine approach
silviuaavram Jun 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CHANGELOG.old.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ A big thanks to the 16 contributors who made this release possible.
- Fix incorrect indentation in migration guide (#47571) @sai6855
- Enable MUI chat on Material UI demos (#46837) @siriwatknp
- Add docs and website banner for Dev survey'25 (#47521) @prakhargupta1
- Update Tailwind CSS v4 + Next.js Pages Router docs (#47546) @atharva3333
- Update Tailwind CSS v4 + Next.js Pages Router docs (#47546) @atharva3333
- Add warning callout to Sync plugin doc (#47511) @mapache-salvaje
- Update typo in TailwindCSS v4 integration with Next.js docs (#47512) @TimKraemer
- Fix link to contributing guide (#47473) @oliviertassinari
Expand Down Expand Up @@ -3738,7 +3738,7 @@ This release was mostly about 🐛 bug fixes and 📚 documentation improvements

- Link to pnpm installation docs (#42420) @aarongarciah
- Remove LocalMonero (@oliviertassinari) (#42315) @github-actions[bot]
- [material-ui] Fix typo in style interoperability with Tailwind CSS docs (@ZeeshanTamboli) (#42312) @github-actions[bot]
- [material-ui] Fix typo in style interoperability with Tailwind CSS docs (@ZeeshanTamboli) (#42312) @github-actions[bot]
- [material-ui][Pagination] Clarify pagination `page` prop API (@Mandar-Pandya) (#42265) @github-actions[bot]
- [material-ui][Tabs] Improve the Basic Tabs demo (@MatheusEli) (#42426) @github-actions[bot]
- [pigment-css] Fix duplication of content (#42410) @oliviertassinari
Expand Down
297 changes: 297 additions & 0 deletions STYLING_V8_TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
# Styling v8 — Emotion-free path TODO

## Goal

Material UI components ship their **own base styles as plain CSS files** (`@layer mui.default`,
driven by `--mui-*` CSS variables). This base layer is shared by all consumers. Users who want
Emotion (`sx`, `styled()`) keep using it without any changes. Users who don't want Emotion
swap the engine and use one of two theme delivery paths.

---

## Path overview

| | **Emotion path** | **Path A — CssThemeProvider** | **Path B — Static CSS** |
|---|---|---|---|
| Engine | `@mui/styled-engine` (Emotion) | `@mui/styled-engine-noop` | `@mui/styled-engine-noop` |
| Base styles | `Component.css` | same | same |
| Theme delivery | `ThemeProvider` (runtime) | `CssThemeProvider` (runtime) | `default-theme.css` (build-time) |
| Custom theme | `createTheme()` → `ThemeProvider` | `createTheme({ cssVariables: true })` → `CssThemeProvider` | `generateThemeCss(createTheme(...))` → import `.css` |
| `useColorScheme()` | ✅ via `ThemeProvider` | ✅ via `CssThemeProvider` | ✅ standalone hook (no provider) |
| SSR flash prevention | ✅ `InitColorSchemeScript` | ✅ `InitColorSchemeScript` | ✅ `InitColorSchemeScript` |
| `useTheme()` (JS values) | ✅ | ✅ | ❌ no theme context |
| `sx` prop | ✅ | ❌ ignored + dev warning | ❌ ignored + dev warning |
| `styled()` overrides | ✅ | ❌ | ❌ |
| Analogy | — | Mantine | Radix Themes |

**Breaking changes policy:** The Emotion path has zero breaking changes. Paths A and B are
opt-in via the engine alias. `sx` is intentionally unsupported on both non-Emotion paths.

---

## Shared prerequisite — Component CSS conversion _(blocks both non-Emotion paths)_

Both non-Emotion paths require components to have their styles extracted to co-located `.css`
files. Without this, components have no base styles on the noop engine. This is the largest
body of work and is independent of the provider/static choice.

### The pattern (established by Slider)

- `Slider.js` — `styled()` calls with empty payloads: `styled('span', { name, slot })({})`.
The engine alias determines at bundle time whether this is Emotion or noop.
- `Slider.css` — all base styles inside `@layer mui.default`, using `--mui-*` CSS variables.
Auto-imported via a side-effect import at the top of `Slider.js`. Users never import it manually.
- Both Emotion and noop users get the same visual output from the same component file.

### CSS file convention

- `@layer mui.default` wrapper for all rules.
- Class naming: `.MuiX-slotName`, `.MuiX-variantName`, `.Mui-stateClass`.
- Logical properties (`inset-block-start`, `inset-inline-start`) instead of `top`/`left`/`right`/`bottom`.
- Media queries: `forced-colors`, `pointer: coarse`, `prefers-reduced-motion`.
- Print: `print-color-adjust: exact` (not the deprecated `color-adjust`).

### TODOs — component conversion

- [ ] Verify `Slider.js` is a full drop-in for `SliderEmotion.js` under the Emotion engine.
- [ ] Remove `SliderEmotion.js`, `SliderEmotion.d.ts`, and the `SliderEmotion` re-exports once confirmed.
- [ ] Convert `Button` as the second pilot (variants × colors × states, ripple, focus-visible).
- [ ] Capture a repeatable conversion checklist from the Slider + Button work.
- [ ] Inventory remaining components and sequence the rollout.

---

## Shared prerequisite — Engine alias _(blocks both non-Emotion paths)_

Aliasing `@mui/styled-engine` to `@mui/styled-engine-noop` is the single opt-in step for both
non-Emotion paths. The noop engine exists and works. The gap is documentation.

### TODOs — engine alias

- [ ] Document per-bundler alias config (Vite, webpack, Next.js, esbuild).
- [ ] Decide whether to also offer Option B or Option C for zero-config setup, or defer:
- **Option A (chosen approach, documented in `test/noop-vite-sandbox/vite.config.ts`)** —
bundler alias: user adds one alias rule to their bundler config (`@mui/styled-engine` →
`@mui/styled-engine-noop`). Works with any bundler, no import changes required, but requires
touching build config. End-user documentation is still a TODO above.
- **Option B — subpath imports** (e.g. `@mui/material/css/Slider`): a separate set of package
subpaths that resolve directly to the noop variant without any bundler config. Zero setup, but
users must change every component import in their app (`/Slider` → `/css/Slider`), making
migration tedious and mixing Emotion and noop imports in the same tree possible by accident.
- **Option C — `exports` condition**: `package.json` `exports` supports custom conditions (e.g.
`"mui-noop"`). Users activate it with a single bundler option (e.g. `resolve.conditions:
['mui-noop']` in Vite), and all `@mui/material` imports automatically resolve to the noop
variant — no alias, no import changes. Cleanest DX, but custom conditions have uneven bundler
support and add permanent complexity to the package's `exports` map.
- [ ] Add a CI test: build the non-Emotion entry point, assert **zero** `@emotion/*` modules.
- [ ] Improve the noop engine dev warning: link to the migration guide, fire once per
component type rather than per instance.

### Done — engine alias

- ✅ `@mui/styled-engine-noop` — zero-runtime passthrough, warns on `sx`, stubs `keyframes`/`css`.
- ✅ Confirmed: production build of `test/noop-vite-sandbox` contains zero `@emotion/*` runtime.
(The `__emotion_real` string in the output is a property-name guard in `@mui/system/createStyled`,
not an import.)
- ✅ Two gotchas documented for Vite: `process.env.NODE_ENV` must be defined via `vite.config.ts`
`define`; a JSX-in-`.js` transform plugin is required because MUI source uses `.js` + JSX.

---

## Path A — CssThemeProvider _(non-Emotion, runtime)_

The Mantine analogy. Users write `createTheme()` in JS, pass it to a provider. The provider
renders CSS variables into the document at runtime — no Emotion, no build step. API-identical
to `ThemeProvider` minus `sx` and `styled()`.

### What users need to do (Path A)

```tsx
// 1. Alias engine in bundler config (see §Engine alias above)

// 2. Create a theme (must use cssVariables: true)
import { createTheme } from '@mui/material/styles';
const theme = createTheme({ cssVariables: true, colorSchemes: { light: true, dark: true } });

// 3. Wrap the app — no ThemeProvider, no Emotion
import { CssThemeProvider } from '@mui/material/styles';
<CssThemeProvider theme={theme}>
<App />
</CssThemeProvider>

// 4. Dark mode toggle
import { useColorScheme } from '@mui/material/styles'; // from CssThemeProvider context
const { mode, setMode } = useColorScheme();
setMode('dark');

// 5. JS theme values (breakpoints, transitions, spacing)
import { useTheme } from '@mui/material/styles';
const theme = useTheme(); // theme.breakpoints.up('md'), etc.
```

SSR flash prevention works the same as with `ThemeProvider`: place `<InitColorSchemeScript />`
in `<head>` before React hydrates. No extra steps specific to `CssThemeProvider` — once
`useCurrentColorScheme` is wired inside it with the same default storage keys and attribute,
`InitColorSchemeScript` is automatically compatible.

### TODOs — Path A

- [ ] Build `CssThemeProvider` as a real provider:
- Wire `useCurrentColorScheme` internally using the same defaults as `ThemeProvider`
(`modeStorageKey: 'mui-mode'`, `colorSchemeStorageKey: 'mui-color-scheme'`,
`attribute: 'data-mui-color-scheme'`) so `InitColorSchemeScript` works out of the box
without any extra user steps.
- Provide a theme context so `useTheme()` works (currently missing despite JSDoc claiming otherwise).
- `disableTransitionOnChange` to suppress CSS transitions during color scheme switch.
- `defaultMode` prop (`'light' | 'dark' | 'system'`).
- `noSsr` prop to skip the hydration-safe default and read localStorage on first render,
matching `CssVarsProvider`'s `noSsr` behavior.
- [ ] Fix `CssVarsInjector` for nested providers: use scoped injection (not a global
`<style id="mui-css-vars">`) so two `CssThemeProvider` instances don't overwrite each other.
- [ ] Verify SSR: `CssVarsInjector` renders a `<style>` tag server-side; confirm no FOUC in
Next.js App Router and Pages Router.
- [ ] Verify `documentNode` (iframe support).

### Done — Path A

- ✅ `CssVarsInjector` — injects CSS vars into document; renders `<style>` server-side, uses
`useInsertionEffect` client-side.
- ✅ `RtlProvider` and `DefaultPropsProvider` wired in the current stub.
- ✅ `CssThemeProvider` validates that the theme was created with `cssVariables: true`.

---

## Path B — Static CSS _(non-Emotion, build-time)_

The Radix Themes analogy. A pre-generated `.css` file contains all `--mui-*` CSS variables for
light and dark. Import it once. No provider, no JS runtime cost.

### What users need to do (Path B)

```tsx
// 1. Alias engine in bundler config (see §Engine alias above)

// 2. Import the pre-generated theme CSS once at the app root
import '@mui/material/default-theme.css';
// (or a custom-generated file — see §Custom theme below)

// 3. SSR flash prevention (put in <head> before React hydrates)
import InitColorSchemeScript from '@mui/material/InitColorSchemeScript';
<InitColorSchemeScript />
// In a Vite SPA (no SSR), extract the script text to paste into index.html directly.
// See §getInitColorSchemeScriptText below.

// 4. Dark mode toggle — standalone hook, no provider
import { useColorScheme } from '@mui/material/colorScheme'; // Emotion-free subpath
const { mode, setMode } = useColorScheme();
setMode('dark'); // writes localStorage + data-mui-color-scheme attribute

// 5. (Optional) custom theme — generate CSS at build time
import { generateThemeCss } from '@mui/material/generateThemeCss';
import { createTheme } from '@mui/material/styles';
// In a build script:
const css = generateThemeCss(createTheme({ palette: { primary: { main: '#e91e63' } } }));
fs.writeFileSync('my-theme.css', css);
// Then import './my-theme.css' instead of default-theme.css
```

### TODOs — Path B

- [ ] **Standalone `useColorScheme` hook** (`@mui/material/colorScheme` — new Emotion-free subpath):
- Reads/writes `data-mui-color-scheme` on `document.documentElement`.
- Persists mode under the same localStorage key as `InitColorSchemeScript` (`mui-mode`).
- Supports `'light' | 'dark' | 'system'`; `'system'` subscribes to
`window.matchMedia('(prefers-color-scheme: dark)')`.
- No Emotion, no React context provider.
- Must not be mixed with `ThemeProvider`'s `useColorScheme` in the same tree.
- [ ] **`getInitColorSchemeScriptText(props?)`** — named export from
`@mui/material/InitColorSchemeScript` that returns the inline script as a string, so Vite SPAs
can paste it directly into `index.html` without a React wrapper.
- [ ] **`generateThemeCss(options: ThemeOptions): string`** — thin wrapper over
`createTheme` + `styleSheetsToString(theme.generateStyleSheets())`. Forces
`colorSchemeSelector: 'data-mui-color-scheme'` so the output matches what
`InitColorSchemeScript` and the standalone hook expect. Published at
`@mui/material/generateThemeCss`.
- [ ] Refactor `buildDefaultThemeCss.mts` to call `generateThemeCss({})` internally.
- [ ] Document: CSS variable overrides (no build step needed for simple changes like
`--mui-palette-primary-main: #e91e63` in plain CSS).
- [ ] Document `InitColorSchemeScript` as standalone (no `ThemeProvider` needed).

### Done — Path B

- ✅ `@mui/material/default-theme.css` — pre-generated, shipped, named `exports` entry.
- ✅ `InitColorSchemeScript` — Emotion-free, same attribute + localStorage keys as
`default-theme.css`.
- ✅ `buildDefaultThemeCss.mts` — internal build script that generates `default-theme.css`.
- ✅ Component `.css` files auto-imported by component JS files (no manual import needed).
- ✅ `test/noop-vite-sandbox` — Slider rendered on Path B with dark mode toggle (DOM-only).

---

## Comparison with Mantine and Radix Themes

### Mantine → Path A (CssThemeProvider)

Mantine dropped CSS-in-JS entirely in v7 and replaced it with CSS Modules + a runtime provider
(`MantineProvider`) that injects CSS variables. Users still call `createTheme()` in JS and pass
it as a prop. No build step for theming.

**Key differences from MUI Path A:**
- Mantine uses hashed CSS Module class names — no stable `.Mantine*` customization surface.
MUI keeps stable `.Mui*` class names; `@layer` solves the specificity problem without
sacrificing the class-name contract.
- Mantine dropped CSS-in-JS with no compatibility layer. MUI's Path A co-exists with the
Emotion path — users migrate at their own pace.

### Radix Themes → Path B (Static CSS)

Radix Themes ships all styles as static CSS files. Theme tokens are CSS variables. No runtime,
no JS theming engine. Customization is CSS variable overrides or a palette generation tool.

**Key differences from MUI Path B:**
- Radix's token space is fixed (12-step Radix Colors scales, ~6 accent choices). MUI has
~400 computed variables — palette channels, alpha overlays, typography scale — derived from
`createTheme()`. The build-time `generateThemeCss()` fills this gap.
- Radix has no `sx` on any path. MUI's Path B coexists with the Emotion path.

### MUI's advantage over both

Neither library offers both a zero-runtime path and a full `sx`/`styled()` path from the same
component files. MUI will be the first to do this.

---

## Shared — Customization contract (`@layer`)

- [ ] Document the override model: unlayered user CSS (and Tailwind v4 utilities) always win
over `@layer mui.default` — no specificity fight, no `!important`.
- [ ] Validate layer ordering with Tailwind v3 (`@mui/tailwind` preset) and v4 (`@mui/tailwind/v4.css`).
- [ ] Verify `slotProps.className` / `className` compose correctly with layered base styles for
all converted components.
- [ ] Confirm: Emotion-generated class names (from `sx` / `styled()`) are not in any layer, so
they also win over `@layer mui.default` automatically.

---

## Shared — Bundle size validation

- ✅ `test/noop-vite-sandbox` — Slider, Path B (static CSS). Baseline: **276 KB raw / 88 KB gzip JS**, 32 KB CSS.
- ✅ `test/css-theme-provider-vite-sandbox` — Slider, Path A (CssThemeProvider, noop engine). Built; JS delta vs noop baseline to be measured.
- ✅ `test/emotion-vite-sandbox` — Slider, Emotion path (ThemeProvider). Built; JS delta vs noop baseline to be measured.
- [ ] Record actual bundle sizes for all three sandboxes and document the deltas in this file.
- [ ] Add to size-snapshot tooling: regression if Emotion leaks into a non-Emotion build.

---

## Shared — Tests, types, docs

- [ ] Run existing Slider tests under the Emotion engine — confirm no regression.
- [ ] Run the same Slider tests under the noop engine — confirm visual and behavioral parity.
- [ ] Update `index.d.ts` after `SliderEmotion` is removed.
- [ ] Docs — Emotion path: note that base styles now come from a CSS file; `sx`/`styled()`
overrides layer on top as before.
- [ ] Docs — Path A: `CssThemeProvider` setup guide, migration from `ThemeProvider`.
- [ ] Docs — Path B: static CSS setup, `InitColorSchemeScript`, standalone `useColorScheme`,
`generateThemeCss()`, CSS variable overrides, Tailwind integration.
- [ ] Clean up experiment pages (`static-theme-playground`, `slider-*-benchmark`,
`css-playground`, `emotion-playground`, `tailwind-playground`) before productionizing.
Loading
Loading