# Material UI (MUI) Administrator & Developer Guide

## 1. Architecture Overview

Material UI is a monorepo hosting 12 publishable npm packages that together form a layered React component library implementing Google's Material Design. The repository at `mui/material-ui` (commit `3dcaf4b2`, 2026-04-18) contains 41,043 files across 14.7 million source characters, organized as a pnpm workspace with Lerna + Nx for task orchestration.

### Package Dependency Chain

```text
@mui/types
    └── @mui/utils
         └── @mui/private-theming
              └── @mui/system
                   ├── @mui/styled-engine (Emotion, default)
                   │    └── @emotion/react + @emotion/styled
                   └── @mui/styled-engine-sc (styled-components, optional)
                        └── styled-components
                   └── @mui/material (86 components)
                        ├── @mui/lab (incubator)
                        ├── @mui/icons-material (2,100+ SVG icons)
                        ├── @mui/material-nextjs (Next.js SSR)
                        └── @mui/material-pigment-css (zero-runtime CSS)
```

### Component Inventory

| Package | Published Name | Contents |
|---|---|---|
| `packages/mui-material` | `@mui/material` | 86 React components, 4 hooks, utility functions, 60+ locales, color palettes |
| `packages/mui-system` | `@mui/system` | Theming engine, `sx` prop, styled(), layout components (Box, Grid, Stack, Container), breakpoints, spacing, CSS variables provider |
| `packages/mui-utils` | `@mui/utils` | ~50 low-level utilities (debounce, deepmerge, composeClasses, fork ref, focus management, etc.) |
| `packages/mui-lab` | `@mui/lab` | Incubator: LoadingButton, Masonry, Timeline, TabContext/TabList/TabPanel, plus deprecated date picker re-exports |
| `packages/mui-icons-material` | `@mui/icons-material` | 2,100+ auto-generated SVG icon components in 5 variants (Filled, Outlined, Rounded, Sharp, TwoTone) |
| `packages/mui-styled-engine` | `@mui/styled-engine` | Emotion adapter: styled(), keyframes, css, GlobalStyles, StyledEngineProvider |
| `packages/mui-styled-engine-sc` | `@mui/styled-engine-sc` | styled-components adapter (drop-in replacement) |
| `packages/mui-types` | `@mui/types` | TypeScript utility types: OverridableComponent, DistributiveOmit, OverridableStringUnion |
| `packages/mui-private-theming` | `@mui/private-theming` | Minimal ThemeProvider + useTheme (internal, lowest layer) |
| `packages/mui-codemod` | `@mui/codemod` | jscodeshift + postcss migration transforms (v5→v6→v7→v9 and deprecation codemods) |
| `packages/mui-material-nextjs` | `@mui/material-nextjs` | Next.js App/Pages Router cache providers (v13, v15 variants) |
| `packages/mui-material-pigment-css` | `@mui/material-pigment-css` | Zero-runtime Pigment CSS integration (PigmentContainer, PigmentGrid, PigmentStack) |
| `packages/mui-envinfo` | `@mui/envinfo` | CLI environment diagnostic tool |
| `packages/mui-core-downloads-tracker` | `@mui/core-downloads-tracker` | Empty package for npm download counting |

> [!NOTE]
> The `@mui/icons-material/lib` directory alone accounts for 10,750 files and 8.5 million characters (58% of the repo by size). Each icon is a thin wrapper around `createSvgIcon()` with the SVG path data inlined.

### Technology Stack

| Layer | Technology | Version |
|---|---|---|
| Language | TypeScript | 5.9.3 |
| Runtime | React | ^17.0.0 \|\| ^18.0.0 \|\| ^19.0.0 |
| Package manager | pnpm | 10.33.0 |
| Monorepo orchestration | Lerna + Nx | 9.0.7 / 20.8.4 |
| Build | Babel (JS output) + tsc (declarations only) | 7.29.0 |
| Default styling engine | Emotion | @emotion/react + @emotion/styled |
| Alternative styling engine | styled-components | via @mui/styled-engine-sc |
| Test runner | Vitest | ^4.0.13 |
| Browser testing | Playwright | 1.59.1 |
| E2E testing | Playwright + @testing-library/react | - |
| Bundler (docs site) | Next.js | ^15.5.14 |
| Linting | ESLint 10.1.0 + Stylelint 17.6.0 + markdownlint-cli2 0.22.0 | - |
| Formatting | Prettier | 3.8.1 |

### Data Flow: Component Rendering

```text
User JSX:
  <Button variant="contained" sx={{ m: 2 }}>Click</Button>
     │
     ▼
DefaultPropsProvider resolves theme defaults:
  theme.components.MuiButton.defaultProps → merged with user props
     │
     ▼
styled() (via @mui/styled-engine / Emotion):
  Applies base styles + variant-based conditional styles
  Processes sx prop via styleFunctionSx (shorthand → CSS → responsive)
     │
     ▼
useSlot() resolves slot composition:
  Root slot: applies component prop (polymorphism)
  Named slots: merge slotProps (className, style, sx, event handlers)
     │
     ▼
composeClasses() generates CSS class names:
  MuiButton-root, MuiButton-contained, MuiButton-containedPrimary
     │
     ▼
React renders final DOM with Emotion-injected styles
```

---

## 2. System Requirements

| Requirement | Value |
|---|---|
| Node.js | >= 22.18.0 |
| pnpm | 10.33.0 (enforced via `packageManager` field) |
| React | ^17.0.0 \|\| ^18.0.0 \|\| ^19.0.0 |
| TypeScript | 5.9.3 (development) |
| OS | Any (Linux, macOS, Windows) |
| Disk | ~500 MB for full clone + node_modules |

### Development Dependencies (key)

| Package | Version | Purpose |
|---|---|---|
| `@babel/core` | 7.29.0 | JS compilation |
| `vitest` | ^4.0.13 | Test runner |
| `vite` | ^7.2.2 | Test/build tooling |
| `playwright` | 1.59.1 | Browser automation |
| `eslint` | 10.1.0 | Linting |
| `prettier` | 3.8.1 | Code formatting |
| `lerna` | 9.0.7 | Monorepo versioning/publishing |
| `nx` | 20.8.4 | Task orchestration |
| `concurrently` | 9.2.1 | Parallel script execution |
| `cross-env` | 10.1.0 | Cross-platform env vars |
| `tsx` | 4.21.0 | TypeScript execution |
| `dotenv` | 17.4.0 | .env loading |

---

## 3. Configuration Reference

### Theme Configuration Object

The `createTheme()` function accepts the following top-level keys:

| Key | Type | Purpose |
|---|---|---|
| `palette` | object | Colors: primary, secondary, error, warning, info, success, text, background, divider, action, mode |
| `typography` | object/function | Font families, sizes, weights for h1-h6, subtitle1-2, body1-2, button, caption, overline |
| `spacing` | number/function | Base spacing unit (default: 8px) |
| `breakpoints` | object | Responsive breakpoint values and unit |
| `shape` | object | `borderRadius` (default: 4) |
| `transitions` | object | Duration, easing curves |
| `zIndex` | object | z-index values for mobileStepper, fab, speedDial, appBar, drawer, modal, snackbar, tooltip |
| `components` | object | Per-component `defaultProps`, `styleOverrides`, and `variants` |
| `shadows` | array | 25 shadow values (0-24 elevation levels) |
| `mixins` | object | `toolbar` mixin for AppBar height |
| `direction` | `'ltr'` \| `'rtl'` | Text direction |

### Default Breakpoints

| Key | Default (px) |
|---|---|
| `xs` | 0 |
| `sm` | 600 |
| `md` | 900 |
| `lg` | 1200 |
| `xl` | 1536 |

Breakpoint helpers: `theme.breakpoints.up('sm')`, `down('md')`, `between('sm', 'lg')`, `only('md')`, `not('xs')`.

### Default Palette (Light Mode)

| Token | Default Value |
|---|---|
| `primary.main` | `#1976d2` |
| `primary.light` | computed via `lighten()` |
| `primary.dark` | computed via `darken()` |
| `primary.contrastText` | computed via `getContrastRatio()` |
| `secondary.main` | `#9c27b0` |
| `error.main` | `#d32f2f` |
| `warning.main` | `#ed6c02` |
| `info.main` | `#0288d1` |
| `success.main` | `#2e7d32` |
| `text.primary` | `rgba(0,0,0,0.87)` |
| `text.secondary` | `rgba(0,0,0,0.6)` |
| `background.default` | `#fff` |
| `background.paper` | `#fff` |
| `divider` | `rgba(0,0,0,0.12)` |

### The `sx` Prop Configuration Map

The `sx` prop is powered by `defaultSxConfig.js` which maps shorthand properties to CSS properties, theme keys, and transform functions:

| Category | Shorthands |
|---|---|
| **Spacing** | `m`, `mt`, `mr`, `mb`, `ml`, `mx`, `my`, `p`, `pt`, `pr`, `pb`, `pl`, `px`, `py`, `margin*`, `padding*` (including logical properties: `marginInline`, `paddingBlock`, etc.) |
| **Palette** | `color`, `bgcolor` (`background-color`), `backgroundColor` |
| **Borders** | `border`, `borderTop`, `borderRight`, `borderBottom`, `borderLeft`, `borderColor`, `borderRadius` |
| **Display** | `display`, `overflow`, `textOverflow`, `visibility`, `whiteSpace` |
| **Flexbox** | `flexBasis`, `flexDirection`, `flexWrap`, `justifyContent`, `alignItems`, `alignContent`, `order`, `flex`, `flexGrow`, `flexShrink`, `alignSelf`, `justifyItems`, `justifySelf` |
| **Grid** | `gap`, `columnGap`, `rowGap`, `gridColumn`, `gridRow`, `gridAutoFlow`, `gridAutoColumns`, `gridAutoRows`, `gridTemplateColumns`, `gridTemplateRows`, `gridTemplateAreas`, `gridArea` |
| **Positions** | `position`, `zIndex`, `top`, `right`, `bottom`, `left` |
| **Shadows** | `boxShadow` → maps to `theme.shadows` |
| **Sizing** | `width`, `maxWidth`, `minWidth`, `height`, `maxHeight`, `minHeight`, `boxSizing` |
| **Typography** | `fontFamily`, `fontSize`, `fontStyle`, `fontWeight`, `letterSpacing`, `textTransform`, `lineHeight`, `textAlign`, `typography` |

> [!IMPORTANT]
> Each spacing shorthand resolves values through `theme.spacing()`. Numbers are multiplied by the base (default 8px). Strings pass through as-is. Palette shorthands resolve dot-notation paths (e.g., `'primary.main'`) against `theme.palette`.

### Environment Variables

| Variable | Context | Purpose |
|---|---|---|
| `GITHUB_TOKEN` | Release | Required for changelog generation |
| `CIRCLE_TOKEN` | CI | CircleCI pipeline triggers |
| `CIRCLE_BRANCH` | CI | Current branch in CircleCI |
| `NODE_ENV` | Build/Test | `production` for docs build, regression tests |
| `CI` | Test | `'true'` enables a11y tree exclusion checks |
| `TEST_SCOPE` | Test | `node` or `browser` — controls which Vitest suite runs |
| `VITEST_BROWSERS` | Test | `firefox,webkit` — additional browser targets |
| `TZ` | Test | `UTC` — timezone for test suite |
| `UV_THREADPOOL_SIZE` | Build | `64` — parallelism for icon build |
| `DOCS_STATS_ENABLED` | Docs | `true` — enables webpack bundle analyzer |
| `NEXT_PUBLIC_MUI_LICENSE` | Docs | MUI X license key for docs site |
| `NETLIFY_SITE_NAME` | Deploy | Netlify site identifier |
| `DEPLOY_ENV` | Docs | Deployment environment flag |
| `SOURCE_CODE_REPO` | Docs | Source repo URL for "edit this page" links |
| `PLAYWRIGHT_TEST_BASE_URL` | Test | Base URL for Playwright tests |
| `LIB_VERSION` | Docs | Library version displayed on docs site |
| `CONTEXT` | Build | Netlify build context |
| `DEPLOY_PRIME_URL` | Build | Netlify deploy preview URL |
| `HEAD` | Build | Git HEAD reference |

### Codemod CLI Reference

```bash
npx @mui/codemod <transform> <paths...> [options]
```

| Option | Default | Description |
|---|---|---|
| `--dry` | false | Dry run — no file changes |
| `--parser` | `tsx` | Parser: `babel`, `ts`, `tsx`, `flow` |
| `--print` | false | Print transformed output to stdout |
| `--jscodeshift` | - | Pass-through flags to jscodeshift |
| `--packageName` | `@mui/material` | Target package name for transforms |

**Available transforms:**

| Category | Transforms |
|---|---|
| **v6.0.0** | `all`, `grid-v2-props`, `styled`, `sx-prop`, `system-props`, `theme-v6` |
| **v7.0.0** | `all`, `grid-props`, `input-label-size-normal-medium`, `lab-removed-components`, `theme-color-functions` |
| **v9.0.0** | `system-props` |
| **Deprecations** | `accordion-props`, `alert-classes`, `autocomplete-props`, `avatar-group-props`, `backdrop-props`, `button-classes`, `card-header-props`, `checkbox-props`, `chip-classes`, `dialog-props`, `divider-props`, `drawer-props`, `filled-input-props`, `input-props`, `linear-progress-classes`, `menu-item-props`, `mobile-stepper-props`, `modal-props`, `outlined-input-props`, `pagination-props`, `popover-props`, `popper-props`, `select-props`, `skeleton-props`, `slider-props`, `snackbar-props`, `step-content-props`, `switch-props`, `table-sort-label-props`, `text-field-props`, `toggle-button-group-props`, `tooltip-props`, `typography-props` |

---

## 4. Deployment & Scaling

### Bundle Optimization

MUI packages declare `"sideEffects": false` for tree-shaking. Recommended import patterns:

```javascript
// Path import (always tree-shakeable)
import Button from '@mui/material/Button';

// Named import (requires bundler tree-shaking support)
import { Button } from '@mui/material';
```

Icons are the biggest bundle risk. Each `@mui/icons-material` icon is a separate module with CJS + ESM dual format:
```json
{
  "require": "./Delete.js",
  "import": "./esm/Delete.js",
  "default": "./esm/Delete.js"
}
```

### Bundling Test Matrix

The repository tests bundling compatibility with:

| Bundler | Version | Config |
|---|---|---|
| esbuild | 0.25.0 | ESM + CJS |
| webpack 5 | via Next.js 14.2.35 | React 18 |
| webpack 4 | via Next.js 14.2.35 | React 17 |
| Vite | 5.4.21 | ESM |
| Snowpack | 3.8.8 | ESM |
| Gatsby | 5.13.7 | webpack |
| Node CJS | native | `require()` |
| Node ESM | native | `import` |

### Server-Side Rendering

#### Next.js Integration

`@mui/material-nextjs` provides cache providers for both routing modes:
- **App Router (v15):** `AppRouterCacheProvider` from `@mui/material-nextjs/v15-appRouter`
- **Pages Router (v15):** Provider from `@mui/material-nextjs/v15-pagesRouter`
- **Pages Router (v13):** Provider from `@mui/material-nextjs/v13-pagesRouter`
- **App Router (v13):** Provider from `@mui/material-nextjs/v13-appRouter`

#### Express SSR

Requires `@emotion/server` for critical CSS extraction:
1. Create a shared Emotion cache instance
2. Create an Emotion server with `createEmotionServer(cache)`
3. Render to string: `renderToString(<CacheProvider value={cache}><App /></CacheProvider>)`
4. Extract chunks: `extractCriticalToChunks(html)`
5. Construct style tags: `constructStyleTagsFromChunks(chunks)`

### Pigment CSS (Zero-Runtime)

`@mui/material-pigment-css` provides build-time CSS extraction via Pigment CSS:
- Eliminates Emotion runtime from production bundles
- Requires bundler plugin: `@pigment-css/nextjs-plugin` or `@pigment-css/vite-plugin`
- Provides replacement components: `PigmentContainer`, `PigmentGrid`, `PigmentStack`
- Current version: `@pigment-css/react 0.0.30` (experimental)

> [!NOTE]
> Pigment CSS is experimental. The API may change. Pin the version with resolutions: `"@pigment-css/*": "0.0.30"`.

---

## 5. Operations

### Development Workflow

```bash
# Clone and install
git clone https://github.com/mui/material-ui.git
cd material-ui
pnpm install

# Start docs site (dev mode)
pnpm docs:dev

# Run unit tests
pnpm test:unit

# Run browser tests
pnpm test:browser

# Run e2e tests
pnpm test:e2e

# Run visual regression tests
pnpm test:regressions

# Lint
pnpm eslint
pnpm stylelint
pnpm markdownlint
pnpm valelint

# Format
pnpm prettier
```

> [!TIP]
> The docs dev server requires significant memory. The production build uses `NODE_OPTIONS=--max_old_space_size=8192`.

### Testing Architecture

| Test Type | Command | Runner | Scope |
|---|---|---|---|
| Unit/Integration | `pnpm test:unit` | Vitest (TZ=UTC) | All packages |
| Node-scoped | `pnpm test:node` | Vitest (TEST_SCOPE=node) | Server-side logic |
| Browser-scoped | `pnpm test:browser` | Vitest + Playwright browsers | Browser-specific behavior |
| E2E (website) | `pnpm test:e2e` | Playwright | Docs site navigation, links |
| Visual regression | `pnpm test:regressions` | Playwright screenshots | Pixel-perfect rendering |
| Bundle size | `test/bundle-size/` | Custom | Package size tracking |
| Module resolution | `test/moduleResolution/` | Node CJS + ESM | Import path validation |

**Custom test matchers:**
- `toWarnDev(message)` — asserts `console.warn` is called with the expected message
- `toErrorDev(message)` — asserts `console.error` is called with the expected message

**Test helpers:**
- `@mui/internal-test-utils/createRenderer` — creates a render function with cleanup
- `@testing-library/react` — DOM queries and interactions
- Coverage: Istanbul via `@vitest/coverage-v8`, HTML report at `coverage/index.html`

> [!TIP]
> Use `pnpm use-react-version <version>` to test against different React versions: `stable`, `next`, `experimental`, `latest`, `^17.0.0`.

### Release Process

1. **Version bump:** `pnpm release:version` (Lerna — no changelog, no push, no git tag)
2. **Generate changelog:** `pnpm release:changelog` (requires `GITHUB_TOKEN`)
3. **Open PR:** Create a PR with version + changelog changes
4. **Merge + publish:** After merge, trigger the GitHub Actions publish workflow at `github.com/mui/material-ui/actions/workflows/publish.yml`
5. **Hotfix:** Branch `release/<PATCH_VERSION>` from last tag, cherry-pick, publish with `--dist-tag` for legacy/canary

### Docs Deployment

- Framework: Next.js ^15.5.14
- Hosting: Netlify (`material-ui.netlify.app`)
- Translation: Crowdin (`crowdin.com/project/material-ui-docs`)
- Branches: `latest` = `mui.com`, `next` = `next.mui.com`, `v*.x` = `v*.mui.com`
- Deploy repo: `material-ui-docs` (separate, `FETCH_HEAD:latest` branch)
- Build: `pnpm docs:build` (Next.js export)
- Deploy: `pnpm docs:deploy` (pushes to deploy repo)

### CI/CD

- **CircleCI:** Primary CI — unit tests, browser tests, visual regressions, bundle size checks
- **GitHub Actions:** Publish workflow, PR checks
- **Netlify:** Deploy previews for docs PRs, edge functions for redirects
- **Performance profiling:** CircleCI `profile` workflow, results at `frontend-public.mui.com/test-profile/:job-number`

---

## 6. Performance

### Bundle Size

MUI components are individually importable. Each component is a separate module. Key size factors:

- **Icons:** `@mui/icons-material` contains 10,750 module files. Always import specific icons, never the package root.
- **Tree-shaking:** All packages declare `sideEffects: false`. Use a bundler that respects this (webpack 5+, Vite, esbuild, Rollup).
- **Styled engine:** Emotion adds ~11KB gzipped to the bundle. Pigment CSS eliminates this at build time.
- **Locale files:** Each locale is a separate module. Import only the locale you need.

### Theme Memoization

MUI uses `unstable_memoTheme()` internally to memoize style functions on theme identity. When the theme object reference doesn't change, styled components skip recalculating their styles. Avoid creating new theme objects on every render:

```tsx
// BAD — new theme object every render
function App() {
  return <ThemeProvider theme={createTheme()}><Child /></ThemeProvider>;
}

// GOOD — stable theme reference
const theme = createTheme();
function App() {
  return <ThemeProvider theme={theme}><Child /></ThemeProvider>;
}
```

### Autocomplete Performance

The Autocomplete component can degrade with very large option sets (~1M items, GitHub issue #33487). Mitigations:
- Implement virtualized rendering via `slots.listbox` with a library like `react-window` or `@tanstack/react-virtual`
- Use server-side filtering to limit the visible option count
- Avoid re-creating the `options` array on every render (use `useMemo`)

---

## 7. Security

### Supply Chain

- All dependencies pinned via `pnpm-lock.yaml`
- Resolution overrides enforce specific versions for critical packages:
  - `@babel/core: 7.29.0`, `@babel/runtime: ^7.29.2`
  - `@pigment-css/*: 0.0.30`
  - `@types/node: 20.19.37`
  - `caniuse-lite: ^1.0.30001784`

### Third-Party Content

- Icons sourced from Google Material Design Icons. Third-party license info for Google Material Icons is not machine-detectable (GitHub issue #47699, open). Manual license review recommended for compliance-sensitive deployments.

### XSS Considerations

- MUI components render user-provided content via React's JSX, which escapes by default
- The `dangerouslySetInnerHTML` pattern is not used in MUI components
- SVG icons use inline path data (no external resource loading)
- The `component` prop allows arbitrary element types — ensure user input is not passed directly to it

### Client-Side Only

MUI is a client-side UI library. It does not:
- Make network requests (no API endpoints — 0 detected by AST extraction)
- Store data persistently
- Handle authentication or authorization
- Process server-side input

> [!WARNING]
> When using MUI's `Link` component or `component` prop with user-provided URLs, validate the URL scheme to prevent `javascript:` protocol injection.

---

## 8. Developer Internals

### Repository Structure

```text
mui/material-ui/
├── packages/                    # Publishable npm packages
│   ├── mui-material/           # @mui/material — 86 components
│   ├── mui-system/             # @mui/system — theming, sx, styled()
│   ├── mui-utils/              # @mui/utils — shared utilities
│   ├── mui-lab/                # @mui/lab — incubator components
│   ├── mui-icons-material/     # @mui/icons-material — 2100+ icons
│   ├── mui-styled-engine/      # @mui/styled-engine — Emotion adapter
│   ├── mui-styled-engine-sc/   # @mui/styled-engine-sc — styled-components adapter
│   ├── mui-types/              # @mui/types — TypeScript utilities
│   ├── mui-private-theming/    # @mui/private-theming — base theme context
│   ├── mui-codemod/            # @mui/codemod — migration transforms
│   ├── mui-material-nextjs/    # @mui/material-nextjs — Next.js SSR
│   ├── mui-material-pigment-css/ # @mui/material-pigment-css
│   ├── mui-envinfo/            # @mui/envinfo — diagnostics CLI
│   ├── mui-core-downloads-tracker/ # Download counter
│   ├── mui-stylis-plugin-rtl/  # RTL styling plugin
│   └── pigment-css-react/      # Pigment CSS React bindings
├── packages-internal/           # Non-published internal packages
│   ├── api-docs-builder/       # API reference page generator
│   ├── api-docs-builder-core/  # Core builder utilities
│   ├── core-docs/              # Shared docs components (Demo, API pages)
│   ├── docs-utils/             # Docs helper utilities
│   ├── markdown/               # Markdown processing
│   ├── scripts/                # typescript-to-proptypes, generate-llms-txt
│   ├── test-utils/             # Test infrastructure
│   └── waterfall/              # Waterfall utility
├── docs/                        # Documentation site (Next.js)
│   ├── pages/                  # Next.js page routes
│   ├── data/                   # Documentation content
│   ├── src/                    # Docs site components
│   ├── translations/           # i18n files
│   └── public/                 # Static assets
├── examples/                    # 13+ framework starter projects
├── test/                        # Integration, e2e, regression, bundling tests
├── scripts/                     # Build scripts (API docs, LLM docs)
├── netlify/                     # Netlify functions and edge functions
└── patches/                     # Patch files for dependencies
```

### Core Architectural Patterns

#### 1. Slot Architecture

Every component follows the `slots`/`slotProps` pattern for deep customization. Internally, this is implemented via the `useSlot()` hook in `packages/mui-material/src/utils/useSlot.ts`:

```typescript
function useSlot(name, parameters) {
  // name: slot name (e.g., 'root', 'input', 'listbox')
  // parameters: { elementType, ownerState, externalForwardedProps, ... }
  // Returns: [ResolvedElementType, mergedProps]
}
```

**Merge behavior in `mergeSlotProps()`:**
- `className` — merged via `clsx()`
- `style` — shallow-merged (external wins on conflict)
- `sx` — concatenated into an array
- Event handlers (`on[A-Z]*`) — auto-composed (both internal and external handlers fire)
- Non-event functions from external props — replace defaults
- All other props — external wins

#### 2. Polymorphic Component Pattern

The `component` prop is typed via `OverridableComponent<TypeMap>` from `@mui/types`:

```typescript
interface ButtonTypeMap {
  props: ButtonOwnProps;
  defaultComponent: 'button';
}

declare const Button: OverridableComponent<ButtonTypeMap>;
```

This ensures props adjust based on the resolved element type (e.g., `component={Link}` adds `to` prop).

#### 3. Variant-Based Styling

Components define conditional styles via `variants` arrays in their styled definitions:

```javascript
const ButtonRoot = styled('button')({
  // base styles
  variants: [
    {
      props: { variant: 'contained', color: 'primary' },
      style: { backgroundColor: 'var(--palette-primary-main)' },
    },
    {
      props: (ownerState) => ownerState.disabled,
      style: { opacity: 0.5 },
    },
  ],
});
```

This replaces the older pattern of conditional CSS based on `ownerState` checks.

#### 4. DefaultPropsProvider (Two-Tier Resolution)

Default props are resolved through a React context chain:

1. **System level** (`@mui/system/DefaultPropsProvider`): `getThemeProps()` resolves from `theme.components[name]`, supporting both v5 (`{ defaultProps: {...} }`) and v6 (flat config) signatures.
2. **Material level** (`@mui/material/DefaultPropsProvider`): Thin wrapper with Material UI type safety (`ComponentsPropsList`).

#### 5. FormControl Integration

Input components (TextField, Select, Checkbox, Switch, Radio) read state from the nearest `FormControl` context:
- `disabled` — from FormControl or local prop (local wins)
- `error` — from FormControl or local prop
- `required` — from FormControl or local prop
- `focused` — managed by FormControl with `onFocus`/`onBlur` forwarding

The internal `SwitchBase` component (shared by Checkbox, Switch, Radio) implements controlled/uncontrolled checked state, ripple, and the slots/slotProps pattern with `root` and `input` slots.

#### 6. CSS Class Generation

Classes are generated via `composeClasses()` + `generateUtilityClass()`:
```javascript
// generateUtilityClass('MuiButton', 'root') → 'MuiButton-root'
// Global states: 'Mui-disabled', 'Mui-focused', 'Mui-error', etc.
```

The `ClassNameGenerator` allows customizing the prefix (e.g., for micro-frontend isolation).

### Styled Engine Adapter Layer

`@mui/styled-engine` provides a uniform API over the actual CSS-in-JS library:

| API | Emotion Implementation | styled-components Implementation |
|---|---|---|
| `styled(tag)` | `@emotion/styled` | `styled-components` (with `.attrs` stripped) |
| `ThemeContext` | `@emotion/react` context | styled-components theme context |
| `keyframes` | `@emotion/react` | `styled-components` |
| `css` | `@emotion/react` | `styled-components` |
| `GlobalStyles` | Emotion `<Global>` wrapper | SC `createGlobalStyle` wrapper |
| `internal_mutateStyles` | Modifies `__emotion_styles` | Modifies `componentStyle.rules` |
| `internal_serializeStyles` | `@emotion/serialize` | Passthrough |
| `shouldForwardProp` | Filters MUI system props | Same filter |

The `Interpolation<Props>` type includes a `variants` array where each variant has `props` (partial match or predicate) and `style` (CSSObject or theme function).

### Internal Tooling

#### TypeScript-to-PropTypes Converter

`packages-internal/scripts/typescript-to-proptypes/src/` (7 files, 59,851 chars) extracts TypeScript type definitions and generates runtime PropTypes for development-mode validation. Uses the TypeScript compiler API for type resolution.

**Known errors:**
- `Error: No types found` — when a component file has no exportable types
- `Error: Program doesn't have source files` — when TS program initialization fails

#### API Docs Builder

`packages-internal/api-docs-builder/` (29 files, 104,575 chars combined) auto-generates the 286 API reference pages in `docs/pages/material-ui/api/`. Uses `react-docgen` + Babel AST traversal to extract JSDoc, props, and slots from component source. The `HookApiBuilder` variant handles hooks specifically, extracting parameters and return values.

**Known errors:**
- `Error: The prop description...` — malformed JSDoc in component source
- `TypeError: resolveType for...` — unresolved TypeScript type
- `Error: Could not load a babel config` — missing Babel configuration
- `Error: Impossible to resolve export specifier` — circular or missing re-exports

#### LLM Docs Builder

`scripts/buildLlmsDocs/index.ts` (21,491 chars) generates LLM-friendly documentation. CLI options: `--grep` (filter), `--outputDir`, `--projectSettings` (required).

**Known errors:**
- `Error: --projectSettings is required` — missing required CLI argument
- `Error: Failed to load project settings from ${path}` — invalid settings file

#### Feature Toggles (Docs Site)

```typescript
// packages-internal/core-docs/src/constants/featureToggle.ts
enable_website_banner: true
enable_docsnav_banner: true
enable_job_banner: false
```

### Code Conventions

| Convention | Pattern |
|---|---|
| Component exports | Default export + named type re-exports + `*Classes` object |
| CSS classes | `Mui{ComponentName}-{slot}` (e.g., `MuiButton-root`) |
| Global states | `Mui-disabled`, `Mui-focused`, `Mui-error`, `Mui-selected`, `Mui-checked` |
| Internal APIs | Prefixed with `unstable_` (e.g., `unstable_composeClasses`) |
| Component naming | PascalCase, matches Material Design component name |
| Prop types | TypeScript interfaces with `{Component}Props` naming |
| Theme keys | camelCase matching component name without `Mui` prefix |
| Deprecated exports | Re-exported with console warning, pointing to new package |

### Testing Strategy

- **Unit tests:** Every component has tests using `@testing-library/react` assertions
- **Visual regression:** Playwright screenshots compared pixel-by-pixel in `test/regressions/screenshots/chrome/`
- **Bundle validation:** Each bundler fixture imports every component and validates `ReactIs.isValidElementType()`
- **Module resolution:** Tests both CJS `require()` and ESM `import` paths resolve correctly
- **Multi-React:** CI tests against React 17 and React next/experimental via `pnpm use-react-version`
- **Cross-browser:** Chromium (default) + Firefox + WebKit via `VITEST_BROWSERS`

### Known Issues

| Issue | Component | Status | Impact |
|---|---|---|---|
| #40843 | Autocomplete | Open | Options DOM present when empty in freeSolo |
| #40250 | Autocomplete | Open | Scroll resets when appending options |
| #48177 | Autocomplete | Open | Highlight sync issue in multiple mode |
| #40184 | Autocomplete | Open | Highlighted index not reset on same-length option change |
| #29345 | All | Open | Material Design 3 adoption (feature request) |
| #33487 | Autocomplete | Open | Performance with ~1M items |
| #19886 | Select | Open | NVDA doesn't announce helper text |
| #42622 | Dialog | Open | ChromeVox navigation into Dialog |
| #30468 | ListSubheader | Open | Dark-mode Paper background mismatch |
| #48269 | Codemod | Open | v9 codemod + unplugin-auto-import incompatibility |
| #18450 | Autocomplete | Open | Pagination support for async |
| #38714 | Autocomplete | Open | Virtualization / infinite scroll |
| #47699 | Icons | Open | Third-party license machine-detectability |

### Potential Improvements

1. **Autocomplete reliability** — The Autocomplete component has the highest bug density (7 of 10 reported bugs). Highlight management and scroll behavior are recurring themes.
2. **Accessibility gaps** — Select + NVDA (#19886) and Dialog + ChromeVox (#42622) need `aria-describedby` and navigation fixes.
3. **Material Design 3** — The most-requested feature (#29345). Would require palette, typography, and shape system changes.
4. **Zero-runtime CSS** — Pigment CSS integration is at v0.0.30. Stabilizing this would eliminate the Emotion runtime dependency.
5. **TypeScript strictness** — `exactOptionalPropertyTypes` edge cases (#42694) need type-level fixes.

### Contributing

The repository uses:
- **pnpm** for package management (npm/yarn unsupported)
- **Prettier** + **ESLint** + **Stylelint** + **markdownlint** + **Vale** for code quality
- **Conventional commits** not enforced, but PRs should describe the change clearly
- **CircleCI** for primary CI, **GitHub Actions** for publish
- **Crowdin** for documentation translations

Development flow:
1. Fork and clone
2. `pnpm install`
3. Create a branch
4. Make changes with tests
5. `pnpm test:unit` (ensure passing)
6. `pnpm prettier` + `pnpm eslint` (ensure clean)
7. Open PR against `master` branch

---

## 9. Integration Points

### Styling Engine (Swappable)

MUI's styled engine is abstracted behind `@mui/styled-engine`. The default is Emotion; styled-components is the alternative. The engine provides:

- `styled(component)(styles)` — enhanced styled function with variant support
- `ThemeContext` — React context for theme
- `keyframes` / `css` — CSS-in-JS primitives
- `GlobalStyles` — global CSS injection
- `StyledEngineProvider` — controls style injection order
- `internal_mutateStyles` / `internal_serializeStyles` — internal hooks for the system layer

Switching engines requires only a bundler alias change — no source code modifications.

### RTL Support

`@mui/stylis-plugin-rtl` provides automatic RTL style flipping. Uses the Stylis plugin API to transform CSS at injection time. Integrated via the Emotion cache:

```tsx
import rtlPlugin from '@mui/stylis-plugin-rtl';
import createCache from '@emotion/cache';

const cacheRtl = createCache({ key: 'muirtl', stylisPlugins: [rtlPlugin] });
```

The system layer also provides `RtlProvider` context for component-level direction control.

### Color Manipulation

`@mui/system` exports color utilities via `colorManipulator`:
- `lighten(color, coefficient)` — lighten a color
- `darken(color, coefficient)` — darken a color
- `alpha(color, value)` — set alpha channel
- `getContrastRatio(foreground, background)` — WCAG contrast ratio
- `emphasize(color, coefficient)` — lighten dark colors, darken light colors

### CSS Variables

The experimental `CssVarsProvider` enables CSS custom property-based theming:
- `unstable_createCssVarsProvider` — factory for CSS vars providers
- `unstable_prepareCssVars` — converts theme tokens to CSS variables
- `unstable_cssVarsParser` — parses CSS variable references
- Enables runtime mode switching (light/dark) without JavaScript theme recalculation

### Container Queries

`cssContainerQueries` from `@mui/system` adds container query support to the theme, enabling responsive styles based on parent container size rather than viewport.

---

_Generated May 2026 from mui/material-ui at 3dcaf4b. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
