Two files, one repository
mui/material-ui ships 1 format across 5 indexed files. The question worth asking is whether the second one says anything the first does not.
| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 1 | 20 | 17 | 3% |
| Commands | 0 | 23 | 2 | 0% |
| Section tags | 5 | 8 | 1 | 36% |
What each file covers
Sections
1 shared · 20 only in A · 17 only in B- − AGENTS.md
- − Package Manager
- − Common Commands
- − Development
- − Building
- − Testing
- − Code Quality
- − API Documentation
- − Docs demos
- − Architecture
- − Code Conventions
- − Errors
- − Component Structure
- − Accessibility Testing
- − in one terminal
- − in another — note no `--`, pnpm forwards args directly
- − Imports
- − Agent Skills
- − Pre-PR Checklist
- − PR Title Format
- + Material UI and Next.js
- + Abstract
- + Table of contents
- + App Router (recommended)
- + Dependencies
- + Root layout
- + Optional cache `options`
- + URL hooks and Suspense
- + Pages Router
- + `_document.tsx`
- + `_app.tsx`
- + Optional: custom cache and cascade layers
- + Fonts (`next/font`)
- + CSS theme variables and SSR
- + Other styling stacks (CSS layers)
- + Next.js Link and `component` prop
- + Further reading
- TypeScript
Commands
0 shared · 23 only in A · 2 only in B- − pnpm -F @mui/material add some-package
- − pnpm -F @mui/material build
- − pnpm install
- − pnpm docs:dev
- − pnpm release:build
- − pnpm docs:build
- − pnpm test:unit
- − pnpm test:unit ComponentName
- − pnpm test:unit -t "test name"
- − pnpm test:browser
- − pnpm test:e2e
- − pnpm test:regressions
- − pnpm prettier
- − pnpm eslint
- − pnpm typescript
- − pnpm proptypes && pnpm docs:api
- − pnpm docs:typescript:formatted
- − pnpm test:regressions:server
- − pnpm test:regressions:run -t '/docs-components-buttons/'
- − pnpm test:regressions:run -t '/docs-components-buttons/BasicButtons$'
- − pnpm test:regressions:run -t '/docs-components-(buttons|chips)/'
- − pnpm extract-error-codes
- − pnpm vale <file1> <file2> ...
- + pnpm add @mui/material-nextjs @emotion/cache
- + pnpm add @mui/material-nextjs @emotion/cache @emotion/server
Section tags
5 shared · 8 only in A · 1 only in B- − build
- − test
- − lint-format
- − git-pr
- − api
- − do-not
- − agent-behaviour
- − docs
- + dependencies
- setup
- code-style
- architecture
- types
- ui
Line diff
mui/material-ui · AGENTS.md
@@ −1 @@
1# AGENTS.md
2
3This file provides guidance for AI agents working with code in this repository.
4
5## Package Manager
6
7**Only pnpm is supported** (yarn/npm will fail). Use the `-F` flag for workspace operations:
8
9```bash
10pnpm -F @mui/material add some-package # Add dependency to a package
11pnpm -F @mui/material build # Build a specific package
12```
13
14Never use `cd` to navigate into package directories for commands.
15
16## Common Commands
17
18### Development
19
20```bash
21pnpm install # Install deps if necessary
22pnpm docs:dev # Start docs dev server only
23```
24
25### Building
26
27```bash
28pnpm release:build # Build all packages (except docs)
29pnpm docs:build # Build documentation site
30```
31
32### Testing
33
34```bash
35pnpm test:unit # Run all unit tests (jsdom)
36pnpm test:unit ComponentName # Run tests matching pattern
37pnpm test:unit -t "test name" # Grep for specific test name
38pnpm test:browser # Run tests in real browsers (Chrome, Firefox, WebKit)
39pnpm test:e2e # End-to-end tests
40pnpm test:regressions # Visual regression tests
41```
42
43### Code Quality
44
45```bash
46pnpm prettier # Format staged changes
47pnpm eslint # Lint with cache
48pnpm typescript # Type check all packages
49```
50
51### API Documentation
52
53After changing component props or TypeScript declarations:
54
55```bash
56pnpm proptypes && pnpm docs:api
57```
58
59### Docs demos
60
61Always author the TypeScript version of the demos. To generate the JavaScript variant, run:
62
63```bash
64pnpm docs:typescript:formatted
65```
66
67## Architecture
68
69This is a monorepo managed by Lerna with Nx for caching. Key packages:
70
71- `@mui/material` - Core Material UI components
72- `@mui/system` - Styling system (sx prop, styled, theme)
73- `@mui/lab` - Experimental components (new components go here first)
74- `@mui/icons-material` - Material Design icons
75- `@mui/utils` - Internal utilities
76- `@mui/styled-engine` - CSS-in-JS abstraction (Emotion by default)
77
78Internal packages (not published): `@mui-internal/*`, `@mui/internal-*`
79
80## Code Conventions
81
82### TypeScript
83
84- Use `interface` (not `type`) for component props
85- Export `{ComponentName}Props` interface from component files
86- Path aliases available: `@mui/material` → `./packages/mui-material/src`
87
88### Errors
89
90These guidelines only apply for errors thrown from public packages.
91
92Every error message must:
93
941. **Say what happened** - Describe the problem clearly
952. **Say why it's a problem** - Explain the consequence
963. **Point toward how to solve it** - Give actionable guidance
97
98Format:
99
100- Prefix with `MUI: `
101- Use string concatenation for readability
102- Include a documentation link when applicable (`https://mui.com/r/...`)
103
104#### Error Minifier
105
106Use the `/* minify-error */` comment to activate the babel plugin:
107
108```tsx
109throw /* minify-error */ new Error(
110 'MUI: Expected valid input target. ' +
111 'Did you use a custom `inputComponent` and forget to forward refs? ' +
112 'See https://mui.com/r/input-component-ref-interface for more info.',
113);
114```
115
116The minifier works with both `Error` and `TypeError` constructors.
117
118#### After Adding/Updating Errors
119
120Run `pnpm extract-error-codes` to update `docs/public/static/error-codes.json`.
121
122**Important:** If the update created a new error code, but the new and original message have the same number of arguments and semantics haven't changed, update the original error in `error-codes.json` instead of creating a new code.
123
124### Component Structure
125
126```text
127packages/mui-material/src/Button/
128├── Button.tsx # Component implementation
129├── Button.d.ts # TypeScript declarations (for JSDoc API docs)
130├── Button.test.js # Unit tests
131├── buttonClasses.ts # CSS classes
132└── index.ts # Public exports
133```
134
135### Testing
136
137- Use `createRenderer()` from `@mui/internal-test-utils`
138- Use Chai BDD-style assertions (`expect(x).to.equal(y)`)
139- Custom matchers: `toErrorDev()`, `toWarnDev()` for console assertions
140- Prefer testing components with full interactions using `user.*` methods. Avoid `fireEvent` and `setProps` if possible.
141- If tests require the browser because, for example, they require layout measurements, restrict it to the Chromium env by using `it.skipIf(isJsdom())` or `describe.skipIf(isJsdom())` (search other tests for example usage if unsure).
142
143```js
144import { createRenderer } from '@mui/internal-test-utils';
145
146describe('Button', () => {
147 const { render } = createRenderer();
148
149 it('renders children', async () => {
150 const handleClick = vi.fn();
151 const { getByRole, user } = render(<Button onClick={handleClick}>Hello</Button>);
152
153 const button = getByRole('button');
154 expect(button).to.have.text('Hello');
155
156 await user.click(button);
157 expect(handleClick).toHaveBeenCalledTimes(1);
158 });
159});
160```
161
162### Accessibility Testing
163
164axe-core runs inside the visual-regression Playwright loop (`test/regressions/index.test.js`) — no separate browser session. Screenshots and a11y are independent: a demo can opt out of one and still run the other.
165
166Key files:
167
168- `test/regressions/demoMeta.ts` — `SCREENSHOT_RULES` and `A11Y_RULES` arrays, matched last-wins (no inheritance: overrides restate every field) against `docs/data/material/components/{slug}/{Demo}` (minimatch globs).
169- `test/regressions/a11y/axe.ts` — asserts `color-contrast` and `link-in-text-block` unless listed in `skipAssertions`.
170- `test/regressions/a11y/a11yReporter.ts` — writes one file per slug at `docs/data/material/components/{slug}/{slug}.a11y.json`. Each file is keyed by demo name, then by axe rule ID. Each rule records a `status` (`pass`, `fail`, or `incomplete`) and WCAG tags.
171
172Enroll a component (slug-wide, or narrow with brace-glob):
173
174```ts
175// test/regressions/demoMeta.ts
176{ test: 'docs/data/material/components/alert/*', enabled: true, skipAssertions: ['color-contrast'] },
177{ test: 'docs/data/material/components/buttons/{BasicButtons,ColorButtons}', enabled: true },
178```
179
180Override a specific demo: append a per-demo rule _after_ the slug-wide rule (last-match-wins; the override must restate every field it wants):
181
182```ts
183{ test: 'docs/data/material/components/popover/AnchorPlayground', enabled: false }, // Redux isolation
184```
185
186Run `pnpm test:regressions` to refresh the `*.a11y.json` files. CI fails if any are stale.
187
188For local iteration, scope the run with vitest's `-t` test-name filter (matched against the `it()` strings, which contain the route). Non-matching tests are skipped — their bodies don't execute, so the browser never navigates to those routes.
189
190```bash
191# in one terminal
192pnpm test:regressions:server
193
194# in another — note no `--`, pnpm forwards args directly
195pnpm test:regressions:run -t '/docs-components-buttons/' # one slug
196pnpm test:regressions:run -t '/docs-components-buttons/BasicButtons$' # one demo
197pnpm test:regressions:run -t '/docs-components-(buttons|chips)/' # multiple slugs
198```
199
200Filtered runs only refresh the matched slugs' `*.a11y.json`. Run the unfiltered `pnpm test:regressions` before pushing.
201
202### Imports
203
204Use one-level deep imports to avoid bundling entire packages:
205
206```js
207import Button from '@mui/material/Button'; // Good
208import { Button } from '@mui/material'; // Avoid in packages
209```
210
211## Agent Skills
212
213Packaged guidance for common integration topics lives under `skills/`. Each skill is a self-contained directory:
214
215| Skill | Focus |
216| :--------------------------------------------------------------------- | :---------------------------------------------------------- |
217| [skills/material-ui-styling](./skills/material-ui-styling/AGENTS.md) | `sx`, `styled()`, theme overrides, slots, global CSS |
218| [skills/material-ui-theming](./skills/material-ui-theming/AGENTS.md) | `createTheme`, design tokens, `colorSchemes`, CSS variables |
219| [skills/material-ui-nextjs](./skills/material-ui-nextjs/AGENTS.md) | App/Pages Router, Emotion cache, `next/font`, `Link`, SSR |
220| [skills/material-ui-tailwind](./skills/material-ui-tailwind/AGENTS.md) | Tailwind v4 `@layer`, `enableCssLayer`, v3 interop |
221
222Read the relevant `AGENTS.md` when helping users with those topics.
223
224## Pre-PR Checklist
225
2261. `pnpm prettier` - Format code
2272. `pnpm eslint` - Pass linting
2283. `pnpm typescript` - Pass type checking
2294. `pnpm test:unit` - Pass unit tests
2305. If API changed: `pnpm proptypes && pnpm docs:api`
2316. If demos changed: `pnpm docs:typescript:formatted`
2327. If `.md` files changed: `pnpm vale <file1> <file2> ...` - Check prose style and grammar
233
234## PR Title Format
235
236`[component] Imperative description`
237
238Examples:
239
240- `[button] Add loading state`
241- `[docs] Fix typo in Grid documentation`
242
mui/material-ui · skills/material-ui-nextjs/AGENTS.md
@@ +1 @@
1# Material UI and Next.js
2
3Version 1.0.0 (Material UI v9)
4
5> **Version notice:** This skill targets Material UI v9 (`>=9.0.0 <10.0.0`). If you are using a different major version, verify the API details before following this guidance.
6
7> Note: This document is for agents and LLMs integrating Material UI with Next.js. Source: `docs/data/material/integrations/nextjs/nextjs.md` and related integration docs in this repository.
8
9---
10
11## Abstract
12
13Material UI uses Emotion for styles. On Next.js you must wire an Emotion cache so SSR and streaming produce correct CSS (prefer injecting styles into `head` instead of only `body`). The `@mui/material-nextjs` package supplies `AppRouterCacheProvider` (App Router) and `AppCacheProvider` / `DocumentHeadTags` (Pages Router). Material UI components ship as client components (`"use client"`); they still SSR but are not React Server Components. Match the package import suffix (for example `v15-appRouter`) to your Next.js major version.
14
15---
16
17## Table of contents
18
191. [App Router (recommended)](#app-router-recommended)
202. [Pages Router](#pages-router)
213. [Fonts (`next/font`)](#fonts-nextfont)
224. [CSS theme variables and SSR](#css-theme-variables-and-ssr)
235. [Other styling stacks (CSS layers)](#other-styling-stacks-css-layers)
246. [Next.js Link and `component` prop](#nextjs-link-and-component-prop)
257. [Further reading](#further-reading)
26
27---
28
29## App Router (recommended)
30
31### Dependencies
32
33Have `@mui/material` and `next` installed, then add:
34
35- `@mui/material-nextjs`
36- `@emotion/cache`
37
38Example: `pnpm add @mui/material-nextjs @emotion/cache`
39
40### Root layout
41
42In `app/layout.tsx`, wrap everything under `<body>` with `AppRouterCacheProvider` from the entry that matches your Next major, for example:
43
44`import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';`
45
46(Use the `v1X-appRouter` path that matches your Next.js version if not on v15.)
47
48Why: it collects CSS from MUI System during server rendering and streaming so styles attach predictably; it is recommended so styles go to `<head>` instead of only `<body>`. See [Next.js integration—Configuration](https://mui.com/material-ui/integrations/nextjs.md#configuration).
49
50### Optional cache `options`
51
52Pass `options` to `AppRouterCacheProvider` to override [Emotion cache options](https://emotion.sh/docs/@emotion/cache#options), for example `key: 'css'` (the default MUI key is `mui`). See [Next.js integration—Custom cache (optional)](https://mui.com/material-ui/integrations/nextjs.md#custom-cache-optional).
53
54### URL hooks and Suspense
55
56Dashboards and internal tools often combine MUI client components with URL-driven UI (filters, tabs, pagination) using `useSearchParams()` from `next/navigation`.
57
58Next.js expects a `<Suspense>` boundary around the part of the tree that uses `useSearchParams` (and similar patterns that opt the route into client-side rendering), otherwise you can get build failures or runtime errors about a missing Suspense boundary.
59
60Practical pattern: keep `app/.../page.tsx` as a server component when possible; render a client subtree that uses components such as `Table`, `Tabs`, or `TextField` and is tied to the query string inside `<Suspense>` from that server page. Do not use `fallback={null}` for UI that occupies layout space (toolbars, filters, and similar); it tends to cause layout shift when the client mounts. Use a fallback that matches the real layout (for example `Skeleton` with `Stack` or `Box` and the same `minHeight` and rough dimensions as the final UI). Full example: [Next.js integration—URL-driven UI and the Suspense boundary](https://mui.com/material-ui/integrations/nextjs.md#url-driven-ui-and-the-suspense-boundary).
61
62Official reference: [Next.js—`useSearchParams`](https://nextjs.org/docs/app/api-reference/functions/use-search-params) (static rendering and Suspense notes vary by major version).
63
64---
65
66## Pages Router
67
68### Dependencies
69
70Add `@mui/material-nextjs`, `@emotion/cache`, and `@emotion/server`.
71
72Example: `pnpm add @mui/material-nextjs @emotion/cache @emotion/server`
73
74### `_document.tsx`
75
76- Import `DocumentHeadTags` and `documentGetInitialProps` from the `v15-pagesRouter` (or matching `v1X-pagesRouter`) entry.
77- Render `<DocumentHeadTags {...props} />` inside `<Head>`.
78- Assign `getInitialProps` to call `documentGetInitialProps`.
79
80### `_app.tsx`
81
82Wrap the app with `AppCacheProvider` from the same major entry (for example `v15-pagesRouter`).
83
84### Optional: custom cache and cascade layers
85
86- Pass a custom `emotionCache` into `documentGetInitialProps` options when needed.
87- For `@layer`, use `createEmotionCache({ enableCssLayer: true })` from `@mui/material-nextjs`, pass it from `_document` and align `_app` with the same cache pattern. See [Next.js integration—Cascade layers (optional)](https://mui.com/material-ui/integrations/nextjs.md#cascade-layers-optional).
88
89### TypeScript
90
91Extend `Document` props with `DocumentHeadTagsProps` from the same import path. See [Next.js integration—TypeScript](https://mui.com/material-ui/integrations/nextjs.md#typescript).
92
93---
94
95## Fonts (`next/font`)
96
97App Router: theme modules that call `createTheme` need `'use client'` when they are consumed from server components. Use `next/font/google` (or local fonts), set `variable: '--font-…'`, put `className={font.variable}` on `<html>` (or as in docs), and set `typography.fontFamily` to `'var(--font-…)'`. Wrap with `ThemeProvider` inside `AppRouterCacheProvider` as needed.
98
99Pages Router: similar pattern in `pages/_app.tsx` with `AppCacheProvider` and `ThemeProvider`.
100
101Details: [Next.js integration—Font optimization](https://mui.com/material-ui/integrations/nextjs.md#font-optimization) (App) and [Next.js integration—Font optimization](https://mui.com/material-ui/integrations/nextjs.md#font-optimization-1) (Pages).
102
103---
104
105## CSS theme variables and SSR
106
107Enable `cssVariables: true` in `createTheme` when using [CSS theme variables](https://mui.com/material-ui/customization/css-theme-variables/overview.md). For SSR flicker and `InitColorSchemeScript`, follow [CSS theme variables—Preventing SSR flickering](https://mui.com/material-ui/customization/css-theme-variables/configuration.md#preventing-ssr-flickering) and [CSS theme variables overview—Advantages](https://mui.com/material-ui/customization/css-theme-variables/overview.md#advantages). Add `suppressHydrationWarning` to `<html>` when using `colorSchemes` — the color scheme attribute is written client-side on first render and will otherwise produce a React hydration mismatch.
108
109---
110
111## Other styling stacks (CSS layers)
112
113If you combine MUI with Tailwind CSS, CSS Modules, or other global CSS, set `enableCssLayer: true` on `AppRouterCacheProvider`:
114
115`<AppRouterCacheProvider options={{ enableCssLayer: true }}>`
116
117That wraps MUI output in `@layer mui` so anonymous layers can override as intended. See [Next.js integration—Using other styling solutions](https://mui.com/material-ui/integrations/nextjs.md#using-other-styling-solutions) and [MDN—@layer](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@layer).
118
119---
120
121## Next.js Link and `component` prop
122
123Next.js v16: passing `next/link` directly into `component` can trigger "Functions cannot be passed directly to Client Components". Fix: a small client re-export:
124
125```tsx
126'use client';
127import Link, { LinkProps } from 'next/link';
128export default Link;
129```
130
131Import that wrapper and use `component={Link}` on `Button` and similar. See [Next.js integration—Next.js v16 Client Component restriction](https://mui.com/material-ui/integrations/nextjs.md#nextjs-v16-client-component-restriction).
132
133Pages Router and theme-wide patterns: see [Routing libraries—Next.js Pages Router](https://mui.com/material-ui/integrations/routing.md#nextjs-pages-router) and the [material-ui-nextjs-pages-router-ts example](https://github.com/mui/material-ui/tree/master/examples/material-ui-nextjs-pages-router-ts).
134
135---
136
137## Further reading
138
139| Topic | Link |
140| :------------------------------- | :----------------------------------------------------------------------------------------------------- |
141| Full integration guide | [Next.js integration](https://mui.com/material-ui/integrations/nextjs.md) |
142| Example (App Router, TypeScript) | [material-ui-nextjs-ts](https://github.com/mui/material-ui/tree/master/examples/material-ui-nextjs-ts) |
143| Routing + Link adapters | [Routing libraries](https://mui.com/material-ui/integrations/routing.md) |
144| RSC vs SSR (terminology) | [React WG discussion](https://github.com/reactwg/server-components/discussions/4) |
145
146Import path cheat sheet: [reference.md](reference.md).
147
@@ −1 +1 @@
1−# AGENTS.md
1+# Material UI and Next.js
22
3−This file provides guidance for AI agents working with code in this repository.
3+Version 1.0.0 (Material UI v9)
44
5−## Package Manager
5+> **Version notice:** This skill targets Material UI v9 (`>=9.0.0 <10.0.0`). If you are using a different major version, verify the API details before following this guidance.
66
7−**Only pnpm is supported** (yarn/npm will fail). Use the `-F` flag for workspace operations:
7+> Note: This document is for agents and LLMs integrating Material UI with Next.js. Source: `docs/data/material/integrations/nextjs/nextjs.md` and related integration docs in this repository.
88
9−```bash
10−pnpm -F @mui/material add some-package # Add dependency to a package
11−pnpm -F @mui/material build # Build a specific package
12−```
9+---
1310
14−Never use `cd` to navigate into package directories for commands.
11+## Abstract
1512
16−## Common Commands
13+Material UI uses Emotion for styles. On Next.js you must wire an Emotion cache so SSR and streaming produce correct CSS (prefer injecting styles into `head` instead of only `body`). The `@mui/material-nextjs` package supplies `AppRouterCacheProvider` (App Router) and `AppCacheProvider` / `DocumentHeadTags` (Pages Router). Material UI components ship as client components (`"use client"`); they still SSR but are not React Server Components. Match the package import suffix (for example `v15-appRouter`) to your Next.js major version.
1714
18−### Development
15+---
1916
20−```bash
21−pnpm install # Install deps if necessary
22−pnpm docs:dev # Start docs dev server only
23−```
17+## Table of contents
2418
25−### Building
19+1. [App Router (recommended)](#app-router-recommended)
20+2. [Pages Router](#pages-router)
21+3. [Fonts (`next/font`)](#fonts-nextfont)
22+4. [CSS theme variables and SSR](#css-theme-variables-and-ssr)
23+5. [Other styling stacks (CSS layers)](#other-styling-stacks-css-layers)
24+6. [Next.js Link and `component` prop](#nextjs-link-and-component-prop)
25+7. [Further reading](#further-reading)
2626
27−```bash
28−pnpm release:build # Build all packages (except docs)
29−pnpm docs:build # Build documentation site
30−```
27+---
3128
32−### Testing
29+## App Router (recommended)
3330
34−```bash
35−pnpm test:unit # Run all unit tests (jsdom)
36−pnpm test:unit ComponentName # Run tests matching pattern
37−pnpm test:unit -t "test name" # Grep for specific test name
38−pnpm test:browser # Run tests in real browsers (Chrome, Firefox, WebKit)
39−pnpm test:e2e # End-to-end tests
40−pnpm test:regressions # Visual regression tests
41−```
31+### Dependencies
4232
43−### Code Quality
33+Have `@mui/material` and `next` installed, then add:
4434
45−```bash
46−pnpm prettier # Format staged changes
47−pnpm eslint # Lint with cache
48−pnpm typescript # Type check all packages
49−```
35+- `@mui/material-nextjs`
36+- `@emotion/cache`
5037
51−### API Documentation
38+Example: `pnpm add @mui/material-nextjs @emotion/cache`
5239
53−After changing component props or TypeScript declarations:
40+### Root layout
5441
55−```bash
56−pnpm proptypes && pnpm docs:api
57−```
42+In `app/layout.tsx`, wrap everything under `<body>` with `AppRouterCacheProvider` from the entry that matches your Next major, for example:
5843
59−### Docs demos
44+`import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';`
6045
61−Always author the TypeScript version of the demos. To generate the JavaScript variant, run:
46+(Use the `v1X-appRouter` path that matches your Next.js version if not on v15.)
6247
63−```bash
64−pnpm docs:typescript:formatted
65−```
48+Why: it collects CSS from MUI System during server rendering and streaming so styles attach predictably; it is recommended so styles go to `<head>` instead of only `<body>`. See [Next.js integration—Configuration](https://mui.com/material-ui/integrations/nextjs.md#configuration).
6649
67−## Architecture
50+### Optional cache `options`
6851
69−This is a monorepo managed by Lerna with Nx for caching. Key packages:
52+Pass `options` to `AppRouterCacheProvider` to override [Emotion cache options](https://emotion.sh/docs/@emotion/cache#options), for example `key: 'css'` (the default MUI key is `mui`). See [Next.js integration—Custom cache (optional)](https://mui.com/material-ui/integrations/nextjs.md#custom-cache-optional).
7053
71−- `@mui/material` - Core Material UI components
72−- `@mui/system` - Styling system (sx prop, styled, theme)
73−- `@mui/lab` - Experimental components (new components go here first)
74−- `@mui/icons-material` - Material Design icons
75−- `@mui/utils` - Internal utilities
76−- `@mui/styled-engine` - CSS-in-JS abstraction (Emotion by default)
54+### URL hooks and Suspense
7755
78−Internal packages (not published): `@mui-internal/*`, `@mui/internal-*`
56+Dashboards and internal tools often combine MUI client components with URL-driven UI (filters, tabs, pagination) using `useSearchParams()` from `next/navigation`.
7957
80−## Code Conventions
58+Next.js expects a `<Suspense>` boundary around the part of the tree that uses `useSearchParams` (and similar patterns that opt the route into client-side rendering), otherwise you can get build failures or runtime errors about a missing Suspense boundary.
8159
82−### TypeScript
60+Practical pattern: keep `app/.../page.tsx` as a server component when possible; render a client subtree that uses components such as `Table`, `Tabs`, or `TextField` and is tied to the query string inside `<Suspense>` from that server page. Do not use `fallback={null}` for UI that occupies layout space (toolbars, filters, and similar); it tends to cause layout shift when the client mounts. Use a fallback that matches the real layout (for example `Skeleton` with `Stack` or `Box` and the same `minHeight` and rough dimensions as the final UI). Full example: [Next.js integration—URL-driven UI and the Suspense boundary](https://mui.com/material-ui/integrations/nextjs.md#url-driven-ui-and-the-suspense-boundary).
8361
84−- Use `interface` (not `type`) for component props
85−- Export `{ComponentName}Props` interface from component files
86−- Path aliases available: `@mui/material` → `./packages/mui-material/src`
62+Official reference: [Next.js—`useSearchParams`](https://nextjs.org/docs/app/api-reference/functions/use-search-params) (static rendering and Suspense notes vary by major version).
8763
88−### Errors
64+---
8965
90−These guidelines only apply for errors thrown from public packages.
66+## Pages Router
9167
92−Every error message must:
68+### Dependencies
9369
94−1. **Say what happened** - Describe the problem clearly
95−2. **Say why it's a problem** - Explain the consequence
96−3. **Point toward how to solve it** - Give actionable guidance
70+Add `@mui/material-nextjs`, `@emotion/cache`, and `@emotion/server`.
9771
98−Format:
72+Example: `pnpm add @mui/material-nextjs @emotion/cache @emotion/server`
9973
100−- Prefix with `MUI: `
101−- Use string concatenation for readability
102−- Include a documentation link when applicable (`https://mui.com/r/...`)
74+### `_document.tsx`
10375
104−#### Error Minifier
76+- Import `DocumentHeadTags` and `documentGetInitialProps` from the `v15-pagesRouter` (or matching `v1X-pagesRouter`) entry.
77+- Render `<DocumentHeadTags {...props} />` inside `<Head>`.
78+- Assign `getInitialProps` to call `documentGetInitialProps`.
10579
106−Use the `/* minify-error */` comment to activate the babel plugin:
80+### `_app.tsx`
10781
108−```tsx
109−throw /* minify-error */ new Error(
110− 'MUI: Expected valid input target. ' +
111− 'Did you use a custom `inputComponent` and forget to forward refs? ' +
112− 'See https://mui.com/r/input-component-ref-interface for more info.',
113−);
114−```
82+Wrap the app with `AppCacheProvider` from the same major entry (for example `v15-pagesRouter`).
11583
116−The minifier works with both `Error` and `TypeError` constructors.
84+### Optional: custom cache and cascade layers
11785
118−#### After Adding/Updating Errors
86+- Pass a custom `emotionCache` into `documentGetInitialProps` options when needed.
87+- For `@layer`, use `createEmotionCache({ enableCssLayer: true })` from `@mui/material-nextjs`, pass it from `_document` and align `_app` with the same cache pattern. See [Next.js integration—Cascade layers (optional)](https://mui.com/material-ui/integrations/nextjs.md#cascade-layers-optional).
11988
120−Run `pnpm extract-error-codes` to update `docs/public/static/error-codes.json`.
89+### TypeScript
12190
122−**Important:** If the update created a new error code, but the new and original message have the same number of arguments and semantics haven't changed, update the original error in `error-codes.json` instead of creating a new code.
91+Extend `Document` props with `DocumentHeadTagsProps` from the same import path. See [Next.js integration—TypeScript](https://mui.com/material-ui/integrations/nextjs.md#typescript).
12392
124−### Component Structure
93+---
12594
126−```text
127−packages/mui-material/src/Button/
128−├── Button.tsx # Component implementation
129−├── Button.d.ts # TypeScript declarations (for JSDoc API docs)
130−├── Button.test.js # Unit tests
131−├── buttonClasses.ts # CSS classes
132−└── index.ts # Public exports
133−```
95+## Fonts (`next/font`)
13496
135−### Testing
97+App Router: theme modules that call `createTheme` need `'use client'` when they are consumed from server components. Use `next/font/google` (or local fonts), set `variable: '--font-…'`, put `className={font.variable}` on `<html>` (or as in docs), and set `typography.fontFamily` to `'var(--font-…)'`. Wrap with `ThemeProvider` inside `AppRouterCacheProvider` as needed.
13698
137−- Use `createRenderer()` from `@mui/internal-test-utils`
138−- Use Chai BDD-style assertions (`expect(x).to.equal(y)`)
139−- Custom matchers: `toErrorDev()`, `toWarnDev()` for console assertions
140−- Prefer testing components with full interactions using `user.*` methods. Avoid `fireEvent` and `setProps` if possible.
141−- If tests require the browser because, for example, they require layout measurements, restrict it to the Chromium env by using `it.skipIf(isJsdom())` or `describe.skipIf(isJsdom())` (search other tests for example usage if unsure).
99+Pages Router: similar pattern in `pages/_app.tsx` with `AppCacheProvider` and `ThemeProvider`.
142100
143−```js
144−import { createRenderer } from '@mui/internal-test-utils';
101+Details: [Next.js integration—Font optimization](https://mui.com/material-ui/integrations/nextjs.md#font-optimization) (App) and [Next.js integration—Font optimization](https://mui.com/material-ui/integrations/nextjs.md#font-optimization-1) (Pages).
145102
146−describe('Button', () => {
147− const { render } = createRenderer();
103+---
148104
149− it('renders children', async () => {
150− const handleClick = vi.fn();
151− const { getByRole, user } = render(<Button onClick={handleClick}>Hello</Button>);
105+## CSS theme variables and SSR
152106
153− const button = getByRole('button');
154− expect(button).to.have.text('Hello');
107+Enable `cssVariables: true` in `createTheme` when using [CSS theme variables](https://mui.com/material-ui/customization/css-theme-variables/overview.md). For SSR flicker and `InitColorSchemeScript`, follow [CSS theme variables—Preventing SSR flickering](https://mui.com/material-ui/customization/css-theme-variables/configuration.md#preventing-ssr-flickering) and [CSS theme variables overview—Advantages](https://mui.com/material-ui/customization/css-theme-variables/overview.md#advantages). Add `suppressHydrationWarning` to `<html>` when using `colorSchemes` — the color scheme attribute is written client-side on first render and will otherwise produce a React hydration mismatch.
155108
156− await user.click(button);
157− expect(handleClick).toHaveBeenCalledTimes(1);
158− });
159−});
160−```
109+---
161110
162−### Accessibility Testing
111+## Other styling stacks (CSS layers)
163112
164−axe-core runs inside the visual-regression Playwright loop (`test/regressions/index.test.js`) — no separate browser session. Screenshots and a11y are independent: a demo can opt out of one and still run the other.
113+If you combine MUI with Tailwind CSS, CSS Modules, or other global CSS, set `enableCssLayer: true` on `AppRouterCacheProvider`:
165114
166−Key files:
115+`<AppRouterCacheProvider options={{ enableCssLayer: true }}>`
167116
168−- `test/regressions/demoMeta.ts` — `SCREENSHOT_RULES` and `A11Y_RULES` arrays, matched last-wins (no inheritance: overrides restate every field) against `docs/data/material/components/{slug}/{Demo}` (minimatch globs).
169−- `test/regressions/a11y/axe.ts` — asserts `color-contrast` and `link-in-text-block` unless listed in `skipAssertions`.
170−- `test/regressions/a11y/a11yReporter.ts` — writes one file per slug at `docs/data/material/components/{slug}/{slug}.a11y.json`. Each file is keyed by demo name, then by axe rule ID. Each rule records a `status` (`pass`, `fail`, or `incomplete`) and WCAG tags.
117+That wraps MUI output in `@layer mui` so anonymous layers can override as intended. See [Next.js integration—Using other styling solutions](https://mui.com/material-ui/integrations/nextjs.md#using-other-styling-solutions) and [MDN—@layer](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@layer).
171118
172−Enroll a component (slug-wide, or narrow with brace-glob):
119+---
173120
174−```ts
175−// test/regressions/demoMeta.ts
176−{ test: 'docs/data/material/components/alert/*', enabled: true, skipAssertions: ['color-contrast'] },
177−{ test: 'docs/data/material/components/buttons/{BasicButtons,ColorButtons}', enabled: true },
178−```
121+## Next.js Link and `component` prop
179122
180−Override a specific demo: append a per-demo rule _after_ the slug-wide rule (last-match-wins; the override must restate every field it wants):
123+Next.js v16: passing `next/link` directly into `component` can trigger "Functions cannot be passed directly to Client Components". Fix: a small client re-export:
181124
182−```ts
183−{ test: 'docs/data/material/components/popover/AnchorPlayground', enabled: false }, // Redux isolation
125+```tsx
126+'use client';
127+import Link, { LinkProps } from 'next/link';
128+export default Link;
184129 ```
185130
186−Run `pnpm test:regressions` to refresh the `*.a11y.json` files. CI fails if any are stale.
131+Import that wrapper and use `component={Link}` on `Button` and similar. See [Next.js integration—Next.js v16 Client Component restriction](https://mui.com/material-ui/integrations/nextjs.md#nextjs-v16-client-component-restriction).
187132
188−For local iteration, scope the run with vitest's `-t` test-name filter (matched against the `it()` strings, which contain the route). Non-matching tests are skipped — their bodies don't execute, so the browser never navigates to those routes.
133+Pages Router and theme-wide patterns: see [Routing libraries—Next.js Pages Router](https://mui.com/material-ui/integrations/routing.md#nextjs-pages-router) and the [material-ui-nextjs-pages-router-ts example](https://github.com/mui/material-ui/tree/master/examples/material-ui-nextjs-pages-router-ts).
189134
190−```bash
191−# in one terminal
192−pnpm test:regressions:server
135+---
193136
194−# in another — note no `--`, pnpm forwards args directly
195−pnpm test:regressions:run -t '/docs-components-buttons/' # one slug
196−pnpm test:regressions:run -t '/docs-components-buttons/BasicButtons$' # one demo
197−pnpm test:regressions:run -t '/docs-components-(buttons|chips)/' # multiple slugs
198−```
137+## Further reading
199138
200−Filtered runs only refresh the matched slugs' `*.a11y.json`. Run the unfiltered `pnpm test:regressions` before pushing.
139+| Topic | Link |
140+| :------------------------------- | :----------------------------------------------------------------------------------------------------- |
141+| Full integration guide | [Next.js integration](https://mui.com/material-ui/integrations/nextjs.md) |
142+| Example (App Router, TypeScript) | [material-ui-nextjs-ts](https://github.com/mui/material-ui/tree/master/examples/material-ui-nextjs-ts) |
143+| Routing + Link adapters | [Routing libraries](https://mui.com/material-ui/integrations/routing.md) |
144+| RSC vs SSR (terminology) | [React WG discussion](https://github.com/reactwg/server-components/discussions/4) |
201145
202−### Imports
203−
204−Use one-level deep imports to avoid bundling entire packages:
205−
206−```js
207−import Button from '@mui/material/Button'; // Good
208−import { Button } from '@mui/material'; // Avoid in packages
209−```
210−
211−## Agent Skills
212−
213−Packaged guidance for common integration topics lives under `skills/`. Each skill is a self-contained directory:
214−
215−| Skill | Focus |
216−| :--------------------------------------------------------------------- | :---------------------------------------------------------- |
217−| [skills/material-ui-styling](./skills/material-ui-styling/AGENTS.md) | `sx`, `styled()`, theme overrides, slots, global CSS |
218−| [skills/material-ui-theming](./skills/material-ui-theming/AGENTS.md) | `createTheme`, design tokens, `colorSchemes`, CSS variables |
219−| [skills/material-ui-nextjs](./skills/material-ui-nextjs/AGENTS.md) | App/Pages Router, Emotion cache, `next/font`, `Link`, SSR |
220−| [skills/material-ui-tailwind](./skills/material-ui-tailwind/AGENTS.md) | Tailwind v4 `@layer`, `enableCssLayer`, v3 interop |
221−
222−Read the relevant `AGENTS.md` when helping users with those topics.
223−
224−## Pre-PR Checklist
225−
226−1. `pnpm prettier` - Format code
227−2. `pnpm eslint` - Pass linting
228−3. `pnpm typescript` - Pass type checking
229−4. `pnpm test:unit` - Pass unit tests
230−5. If API changed: `pnpm proptypes && pnpm docs:api`
231−6. If demos changed: `pnpm docs:typescript:formatted`
232−7. If `.md` files changed: `pnpm vale <file1> <file2> ...` - Check prose style and grammar
233−
234−## PR Title Format
235−
236−`[component] Imperative description`
237−
238−Examples:
239−
240−- `[button] Add loading state`
241−- `[docs] Fix typo in Grid documentation`
146+Import path cheat sheet: [reference.md](reference.md).
242147
