diff --git a/.circleci/config.yml b/.circleci/config.yml index 290ae1aec22cc8..392e1981059680 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -223,6 +223,9 @@ jobs: - run: name: '`yarn proptypes` changes committed?' command: git diff --exit-code + - run: + name: '`yarn rsc:build` changes committed?' + command: git diff --exit-code - run: name: Generate the documentation command: yarn docs:api diff --git a/.eslintrc.js b/.eslintrc.js index ce2431d9577b2c..93b9a674c28484 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -201,6 +201,7 @@ module.exports = { 'react/no-invalid-html-attribute': 'off', 'react/jsx-no-useless-fragment': ['error', { allowExpressions: true }], + 'lines-around-directive': 'off', }, overrides: [ { diff --git a/docs/data/base/getting-started/quickstart/quickstart.md b/docs/data/base/getting-started/quickstart/quickstart.md index cf26c8cda89e5e..8b68a19ecca748 100644 --- a/docs/data/base/getting-started/quickstart/quickstart.md +++ b/docs/data/base/getting-started/quickstart/quickstart.md @@ -2,6 +2,10 @@

Get started with Base UI, a library of headless ("unstyled") React UI components and low-level hooks.

+:::info +If you're using Next.js 13.4 or later, check out the [Next.js App Router guide](/base-ui/guides/next-js-app-router/) +::: + ## Installation `@mui/base` is completely standalone – run one of the following commands to add Base UI to your React project: diff --git a/docs/data/base/guides/next-js-app-router/next-js-app-router.md b/docs/data/base/guides/next-js-app-router/next-js-app-router.md new file mode 100644 index 00000000000000..53cbd75777e329 --- /dev/null +++ b/docs/data/base/guides/next-js-app-router/next-js-app-router.md @@ -0,0 +1,198 @@ +# Next.js App Router + +

Learn how to use Base UI with the Next.js App Router.

+ +:::info +Starting fresh on a new App Router-based project? + +Jump right into the code with this [example repo](https://github.com/mui/material-ui/blob/master/examples/base-next-app-router-ts). +::: + +## Next.js and React Server Components + +The Next.js App Router implements React Server Components, a [new feature](https://github.com/reactjs/rfcs/blob/main/text/0227-server-module-conventions.md#changes-since-v1) introduced in React 18. + +To support the App Router, currently all components and hooks from Base UI and other MUI libraries are exported with the `"use client"` directive. + +:::warning +React Server Components should not be conflated with the concept of server-side rendering (SSR). +So-called Client Components are still server-rendered to HTML. + +For more details, see [this explanation](https://github.com/reactwg/server-components/discussions/4) of Client Components and SSR from the React Working Group. +::: + +## Setting up Base UI with the App Router + +Base UI gives you the freedom to choose your own styling solution, so setting up a Next.js App Router project largely depends on what you choose. +This guide covers Tailwind CSS, Emotion, and other CSS-in-JS solutions like styled-components. + +### Tailwind CSS + +Follow the [Tailwind CSS guide on working with Next.js](https://tailwindcss.com/docs/guides/nextjs), and be sure to add the `app` directory and other directories to `tailwind.config.js`, as shown below: + +```js +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './src/app/**/*.{js,ts,jsx,tsx,mdx}', + './src/components/**/*.{js,ts,jsx,tsx,mdx}' + + // or if not using the `src` directory: + './app/**/*.{js,ts,jsx,tsx,mdx}', + ], + theme: { + extend: {}, + }, + plugins: [], +}; +``` + +Refer to this [example repo](https://github.com/mui/material-ui/blob/master/examples/base-next-app-router-tailwind-ts) for a full working demo of a Next.js 13 app using Base UI and Tailwind CSS. + +### Emotion + +If you're using Emotion, or something Emotion-based like MUI System, create a custom `ThemeRegistry` component that combines the Emotion `CacheProvider`, the Material UI `ThemeProvider`, and the `useServerInsertedHTML` hook from `next/navigation` as follows: + +```tsx +// app/ThemeRegistry.tsx +'use client'; +import createCache from '@emotion/cache'; +import { useServerInsertedHTML } from 'next/navigation'; +import { CacheProvider, ThemeProvider } from '@emotion/react'; +import theme from '/path/to/your/theme'; + +// This implementation is from emotion-js +// https://github.com/emotion-js/emotion/issues/2928#issuecomment-1319747902 +export default function ThemeRegistry(props) { + const { options, children } = props; + + const [{ cache, flush }] = React.useState(() => { + const cache = createCache(options); + cache.compat = true; + const prevInsert = cache.insert; + let inserted: string[] = []; + cache.insert = (...args) => { + const serialized = args[1]; + if (cache.inserted[serialized.name] === undefined) { + inserted.push(serialized.name); + } + return prevInsert(...args); + }; + const flush = () => { + const prevInserted = inserted; + inserted = []; + return prevInserted; + }; + return { cache, flush }; + }); + + useServerInsertedHTML(() => { + const names = flush(); + if (names.length === 0) { + return null; + } + let styles = ''; + for (const name of names) { + styles += cache.inserted[name]; + } + return ( +