Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .cursor/skills/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Cursor skills (symlinks)

Each entry here is a **symlink** to the canonical skill under **`skills/`** at the repository root so Cursor loads **`SKILL.md`** from `.cursor/skills/`.

See **[skills/README.md](../../skills/README.md)** for the catalog and how to add skills.
1 change: 1 addition & 0 deletions .cursor/skills/material-ui-nextjs
1 change: 1 addition & 0 deletions .cursor/skills/material-ui-styling
1 change: 1 addition & 0 deletions .cursor/skills/material-ui-tailwind
1 change: 1 addition & 0 deletions .cursor/skills/material-ui-theming
26 changes: 26 additions & 0 deletions docs/data/material/integrations/nextjs/nextjs.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,32 @@ Then, replace the Next.js Link with the wrapper component:
</Button>
```

### URL-driven UI and the Suspense boundary

When client components use Next.js App Router hooks that read the URL—for example `useSearchParams()` from `next/navigation` for filters, tabs, or pagination—Next.js expects a `<Suspense>` boundary around that part of the React tree.
Without it, you may see build failures or runtime messages about a missing Suspense boundary (behavior depends on your Next.js version and static vs dynamic rendering).

This pattern is common with Material UI: `Table`, `Tabs`, `TextField`, and other controls are often implemented as client components that sync to the query string.

Recommended structure: keep `page.tsx` as a server component when possible, and wrap only the client subtree that calls `useSearchParams` in `<Suspense>`:

```tsx title="app/orders/page.tsx"
import { Suspense } from 'react';
import OrdersToolbar from './OrdersToolbar';

export default function Page() {
return (
<Suspense fallback={null}>
<OrdersToolbar />
</Suspense>
);
}
```

`OrdersToolbar` would be a file marked with `'use client'` that calls `useSearchParams()` and renders Material UI components.

For details and version-specific notes, see the Next.js documentation for [`useSearchParams`](https://nextjs.org/docs/app/api-reference/functions/use-search-params).

## Pages Router

This section walks through the Material UI integration with the Next.js [Pages Router](https://nextjs.org/docs/pages/building-your-application), for both [Server-side Rendering](https://nextjs.org/docs/pages/building-your-application/rendering/server-side-rendering) (SSR) and [Static Site Generation](https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation) (SSG).
Expand Down
51 changes: 51 additions & 0 deletions skills/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Material UI agent skills

Packaged guidance for AI agents and humans. Each skill is a directory under `skills/` with this layout:

```text
skills/
├── README.md # this file
├── material-ui-styling/ # sx vs styled vs theme vs global CSS
│ ├── AGENTS.md # full guide (read for complete detail)
│ ├── SKILL.md # Cursor entry + index
│ ├── README.md
│ ├── metadata.json
│ └── reference.md
├── material-ui-theming/ # createTheme, tokens, dark mode, CSS variables
│ ├── AGENTS.md
│ ├── SKILL.md
│ ├── README.md
│ ├── metadata.json
│ └── reference.md
├── material-ui-nextjs/ # Next.js App/Pages Router, cache, fonts, Link
│ ├── AGENTS.md
│ ├── SKILL.md
│ ├── README.md
│ ├── metadata.json
│ └── reference.md
└── material-ui-tailwind/ # Tailwind v4 layers + v3 interoperability
├── AGENTS.md
├── SKILL.md
├── README.md
├── metadata.json
└── reference.md
```

## Cursor

Symlinks under `.cursor/skills/<skill-name>` point at `skills/<skill-name>` so Cursor loads `SKILL.md` while the canonical content stays in `skills/`.

## Adding a skill

1. Create `skills/<kebab-case-name>/` with `AGENTS.md`, `SKILL.md`, `README.md`, `metadata.json` (optional: `reference.md` or a `rules/` subtree later).
2. Add `ln -s ../../skills/<name> .cursor/skills/<name>` from the repo root (see existing symlinks).
3. List the new skill in the table below.

## Catalog

| Folder | Focus |
| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| [material-ui-styling](./material-ui-styling/) | Choosing styling scope: `sx`, `styled()`, theme overrides, global CSS; slots and state |
| [material-ui-theming](./material-ui-theming/) | Theme object, design tokens, `colorSchemes`, `cssVariables` / `theme.vars`, composition, TS augmentation |
| [material-ui-nextjs](./material-ui-nextjs/) | `@mui/material-nextjs`, App/Pages Router, Emotion cache, `next/font`, CSS layers, Next `Link` + MUI |
| [material-ui-tailwind](./material-ui-tailwind/) | Tailwind v4 `@layer` + `enableCssLayer`; `className` / `slotProps`; v3 preflight / `important` / `injectFirst` |
144 changes: 144 additions & 0 deletions skills/material-ui-nextjs/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Material UI and Next.js

Version 1.0.0

> 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.

---

## Abstract

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.

---

## Table of contents

1. [App Router (recommended)](#app-router-recommended)
2. [Pages Router](#pages-router)
3. [Fonts (`next/font`)](#fonts-nextfont)
4. [CSS theme variables and SSR](#css-theme-variables-and-ssr)
5. [Other styling stacks (CSS layers)](#other-styling-stacks-css-layers)
6. [Next.js Link and `component` prop](#nextjs-link-and-component-prop)
7. [Further reading](#further-reading)

---

## App Router (recommended)

### Dependencies

Have `@mui/material` and `next` installed, then add:

- `@mui/material-nextjs`
- `@emotion/cache`

Example: `pnpm add @mui/material-nextjs @emotion/cache`

### Root layout

In `app/layout.tsx`, wrap everything under `<body>` with `AppRouterCacheProvider` from the entry that matches your Next major, for example:

`import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';`

(Use the `v1X-appRouter` path that matches your Next.js version if not on v15.)

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/#configuration).

### Optional cache `options`

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/#custom-cache-optional).

### URL hooks and Suspense

Dashboards and internal tools often combine MUI client components with URL-driven UI (filters, tabs, pagination) using `useSearchParams()` from `next/navigation`.

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.

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 fallback={…}>` from that server page.

Official reference: [Next.js—`useSearchParams`](https://nextjs.org/docs/app/api-reference/functions/use-search-params) (see static rendering and Suspense notes for your major version). See also [Next.js integration—URL-driven UI and the Suspense boundary](https://mui.com/material-ui/integrations/nextjs/#url-driven-ui-and-the-suspense-boundary).

---

## Pages Router

### Dependencies

Add `@mui/material-nextjs`, `@emotion/cache`, and `@emotion/server`.

Example: `pnpm add @mui/material-nextjs @emotion/cache @emotion/server`

### `_document.tsx`

- Import `DocumentHeadTags` and `documentGetInitialProps` from the `v15-pagesRouter` (or matching `v1X-pagesRouter`) entry.
- Render `<DocumentHeadTags {...props} />` inside `<Head>`.
- Assign `getInitialProps` to call `documentGetInitialProps`.

### `_app.tsx`

Wrap the app with `AppCacheProvider` from the same major entry (for example `v15-pagesRouter`).

### Optional: custom cache and cascade layers

- Pass a custom `emotionCache` into `documentGetInitialProps` options when needed.
- 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/#cascade-layers-optional).

### TypeScript

Extend `Document` props with `DocumentHeadTagsProps` from the same import path. See [Next.js integration—TypeScript](https://mui.com/material-ui/integrations/nextjs/#typescript).

---

## Fonts (`next/font`)

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.

Pages Router: similar pattern in `pages/_app.tsx` with `AppCacheProvider` and `ThemeProvider`.

Details: [Next.js integration—Font optimization](https://mui.com/material-ui/integrations/nextjs/#font-optimization) (App) and [Next.js integration—Font optimization](https://mui.com/material-ui/integrations/nextjs/#font-optimization-1) (Pages).

---

## CSS theme variables and SSR

Enable `cssVariables: true` in `createTheme` when using [CSS theme variables](https://mui.com/material-ui/customization/css-theme-variables/overview/). For SSR flicker and `InitColorSchemeScript`, follow [CSS theme variables—Preventing SSR flickering](https://mui.com/material-ui/customization/css-theme-variables/configuration/#preventing-ssr-flickering) and [CSS theme variables overview—Advantages](https://mui.com/material-ui/customization/css-theme-variables/overview/#advantages).

---

## Other styling stacks (CSS layers)

If you combine MUI with Tailwind CSS, CSS Modules, or other global CSS, set `enableCssLayer: true` on `AppRouterCacheProvider`:

`<AppRouterCacheProvider options={{ enableCssLayer: true }}>`

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/#using-other-styling-solutions) and [MDN—@layer](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@layer).

---

## Next.js Link and `component` prop

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:

```tsx
'use client';
import Link, { LinkProps } from 'next/link';
export default Link;
```

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/#nextjs-v16-client-component-restriction).

Pages Router and theme-wide patterns: see [Routing libraries—Next.js Pages Router](https://mui.com/material-ui/integrations/routing/#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).

---

## Further reading

| Topic | Link |
| -------------------------------- | ------------------------------------------------------------------------------------------------------ |
| Full integration guide | [Next.js integration](https://mui.com/material-ui/integrations/nextjs/) |
| Example (App Router, TypeScript) | [material-ui-nextjs-ts](https://github.com/mui/material-ui/tree/master/examples/material-ui-nextjs-ts) |
| Routing + Link adapters | [Routing libraries](https://mui.com/material-ui/integrations/routing/) |
| RSC vs SSR (terminology) | [React WG discussion](https://github.com/reactwg/server-components/discussions/4) |

Import path cheat sheet: [reference.md](reference.md).
16 changes: 16 additions & 0 deletions skills/material-ui-nextjs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Material UI + Next.js (agent skill)

Integration guide for Material UI with the Next.js App Router and Pages Router: Emotion cache via `@mui/material-nextjs`, `ThemeProvider`, `next/font`, CSS layers with other tools, and `Link` usage.

## Files in this folder

| File | Purpose |
| ------------- | ---------------------------------------- |
| AGENTS.md | Full agent/LLM document |
| SKILL.md | Cursor skill entry (frontmatter + index) |
| metadata.json | Version, abstract, references |
| reference.md | Import paths and layout sketch |

## Cursor

Canonical files live under `skills/`. `.cursor/skills/material-ui-nextjs` should symlink here so Cursor loads SKILL.md.
38 changes: 38 additions & 0 deletions skills/material-ui-nextjs/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: material-ui-nextjs
description: Integrates Material UI with Next.js App and Pages routers using @mui/material-nextjs, Emotion cache providers, next/font, CSS layers with Tailwind/CSS Modules, Link component prop patterns, CSS theme variables SSR notes, and App Router useSearchParams + Suspense. Use when setting up or debugging MUI in a Next.js app.
license: MIT
metadata:
author: mui
version: '1.0.0'
---

# Material UI and Next.js

Agent skill for Next.js + Material UI wiring (SSR/streaming, cache providers, fonts, layers, Link, App Router URL state). SKILL.md is the entry; AGENTS.md is the full guide.

## When to apply

- New App Router or Pages Router app using `@mui/material`
- Styles missing, wrong order, or in `body` instead of `head`
- `next/font` + `ThemeProvider` / `createTheme`
- Tailwind or CSS Modules + MUI (`enableCssLayer`)
- `Button` + `component={Link}` or Next.js v16 client boundary errors
- `useSearchParams` / URL-driven MUI views and Suspense boundaries

## Sections in AGENTS.md

| Area | Topics |
| ------------- | --------------------------------------------------------------------------------------- |
| App Router | `AppRouterCacheProvider`, `@emotion/cache`, `options`, `useSearchParams` + `<Suspense>` |
| Pages Router | `_document`, `_app`, `DocumentHeadTags`, `AppCacheProvider` |
| Fonts | `'use client'` theme, `next/font`, CSS variables on `html` |
| CSS variables | `cssVariables`, SSR flicker docs |
| CSS layers | `enableCssLayer`, Tailwind / other CSS |
| Link | Client wrapper, routing guide, examples repo |

## Full guide

Read [AGENTS.md](./AGENTS.md) for complete steps and doc links.

[reference.md](./reference.md) lists import paths and provider shape.
11 changes: 11 additions & 0 deletions skills/material-ui-nextjs/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "1.0.0",
"organization": "Material UI",
"abstract": "Documents Next.js integration for Material UI: AppRouterCacheProvider and Pages Router Document/App cache wiring, Emotion options, next/font with themes, CSS theme variables and SSR flicker pointers, enableCssLayer for Tailwind/CSS Modules, and Next.js Link client-wrapper patterns.",
"references": [
"https://mui.com/material-ui/integrations/nextjs/",
"https://mui.com/material-ui/integrations/routing/",
"https://github.com/mui/material-ui/tree/master/examples/material-ui-nextjs-ts",
"https://nextjs.org/docs/app"
]
}
28 changes: 28 additions & 0 deletions skills/material-ui-nextjs/reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Material UI + Next.js: reference

## `@mui/material-nextjs` entry points

Pick the `v1X-*` segment that matches the app’s Next.js major (see the package’s README on npm if a new major adds a new entry).

| Router | Typical import path |
| ------------ | ---------------------------------------------------------------------- |
| App Router | `@mui/material-nextjs/v15-appRouter` (or `v14-appRouter`, etc.) |
| Pages Router | `@mui/material-nextjs/v15-pagesRouter` (or matching `v1X-pagesRouter`) |

Pages Router also uses `@emotion/server` for the documented setup; App Router uses `@emotion/cache` only in the default instructions.

## Provider placement (App Router)

```text
<html>
<body>
<AppRouterCacheProvider>
<ThemeProvider theme={theme}> <!-- optional but common -->
{children}
</ThemeProvider>
</AppRouterCacheProvider>
</body>
</html>
```

Order and `next/font` `className` on `html` follow [Next.js integration—Font optimization](https://mui.com/material-ui/integrations/nextjs/#font-optimization).
Loading
Loading