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
@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/libdirectory alone accounts for 10,750 files and 8.5 million characters (58% of the repo by size). Each icon is a thin wrapper aroundcreateSvgIcon()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
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') againsttheme.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
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:
// 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:
{
"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):
AppRouterCacheProviderfrom@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:
- Create a shared Emotion cache instance
- Create an Emotion server with
createEmotionServer(cache) - Render to string:
renderToString(<CacheProvider value={cache}><App /></CacheProvider>) - Extract chunks:
extractCriticalToChunks(html) - 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-pluginor@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
# 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)— assertsconsole.warnis called with the expected messagetoErrorDev(message)— assertsconsole.erroris 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 atcoverage/index.html
Tip
Use
pnpm use-react-version <version>to test against different React versions:stable,next,experimental,latest,^17.0.0.
Release Process
- Version bump:
pnpm release:version(Lerna — no changelog, no push, no git tag) - Generate changelog:
pnpm release:changelog(requiresGITHUB_TOKEN) - Open PR: Create a PR with version + changelog changes
- Merge + publish: After merge, trigger the GitHub Actions publish workflow at
github.com/mui/material-ui/actions/workflows/publish.yml - Hotfix: Branch
release/<PATCH_VERSION>from last tag, cherry-pick, publish with--dist-tagfor 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:latestbranch) - 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
profileworkflow, results atfrontend-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-materialcontains 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:
// 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.listboxwith a library likereact-windowor@tanstack/react-virtual - Use server-side filtering to limit the visible option count
- Avoid re-creating the
optionsarray on every render (useuseMemo)
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.37caniuse-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
dangerouslySetInnerHTMLpattern is not used in MUI components - SVG icons use inline path data (no external resource loading)
- The
componentprop 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
Linkcomponent orcomponentprop with user-provided URLs, validate the URL scheme to preventjavascript:protocol injection.
8. Developer Internals
Repository Structure
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:
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 viaclsx()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:
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:
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:
- System level (
@mui/system/DefaultPropsProvider):getThemeProps()resolves fromtheme.components[name], supporting both v5 ({ defaultProps: {...} }) and v6 (flat config) signatures. - 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 proprequired— from FormControl or local propfocused— managed by FormControl withonFocus/onBlurforwarding
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():
// 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 typesError: 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 sourceTypeError: resolveType for...— unresolved TypeScript typeError: Could not load a babel config— missing Babel configurationError: 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 argumentError: Failed to load project settings from ${path}— invalid settings file
Feature Toggles (Docs Site)
// 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/reactassertions - 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 ESMimportpaths 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
- Autocomplete reliability — The Autocomplete component has the highest bug density (7 of 10 reported bugs). Highlight management and scroll behavior are recurring themes.
- Accessibility gaps — Select + NVDA (#19886) and Dialog + ChromeVox (#42622) need
aria-describedbyand navigation fixes. - Material Design 3 — The most-requested feature (#29345). Would require palette, typography, and shape system changes.
- Zero-runtime CSS — Pigment CSS integration is at v0.0.30. Stabilizing this would eliminate the Emotion runtime dependency.
- TypeScript strictness —
exactOptionalPropertyTypesedge 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:
- Fork and clone
pnpm install- Create a branch
- Make changes with tests
pnpm test:unit(ensure passing)pnpm prettier+pnpm eslint(ensure clean)- Open PR against
masterbranch
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 supportThemeContext— React context for themekeyframes/css— CSS-in-JS primitivesGlobalStyles— global CSS injectionStyledEngineProvider— controls style injection orderinternal_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:
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 colordarken(color, coefficient)— darken a coloralpha(color, value)— set alpha channelgetContrastRatio(foreground, background)— WCAG contrast ratioemphasize(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 providersunstable_prepareCssVars— converts theme tokens to CSS variablesunstable_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.