diff --git a/docs/data/material/migration/migrating-to-v6/migrating-to-pigment-css.md b/docs/data/material/migration/migrating-to-v6/migrating-to-pigment-css.md new file mode 100644 index 00000000000000..ec2b6c887ed853 --- /dev/null +++ b/docs/data/material/migration/migrating-to-v6/migrating-to-pigment-css.md @@ -0,0 +1,518 @@ +# Migrating to Pigment CSS + +

This guide helps you integrate Pigment CSS with Material UI v6.

+ +Before going through this guide, make sure you have Material UI v6 installed. If you have not yet migrated to Material UI v6, follow the [migration guide](/material-ui/migration/migrating-to-v6/) first. + +## Supported frameworks + +Pigment CSS can be used with one of the following frameworks: + +- [Next.js App Router](https://nextjs.org/docs/app/) with Webpack 5 (Turbo is not supported yet) +- [Vite](https://vitejs.dev/) + +## Installation + +First, install the adapter package: + + + +```bash npm +npm install @mui/material-pigment-css +``` + +```bash yarn +yarn add @mui/material-pigment-css +``` + +```bash pnpm +pnpm add @mui/material-pigment-css +``` + + + +Then, follow the instructions based on your framework: + +### Next.js + +Install the Next.js plugin as a dev dependency: + + + +```bash npm +npm install --save-dev @pigment-css/nextjs-plugin +``` + +```bash yarn +yarn add -D @pigment-css/nextjs-plugin +``` + +```bash pnpm +pnpm add -D @pigment-css/nextjs-plugin +``` + + + +Then, open Next.js config file and add the plugin: + + + +```js next.config.mjs +import { withPigment } from '@pigment-css/nextjs-plugin'; + +const nextConfig = { + // ...Your nextjs config. +}; + +/** + * @type {import('@pigment-css/nextjs-plugin').PigmentOptions} + */ +const pigmentConfig = {}; // we will refer to this later + +export default withPigment(nextConfig, pigmentConfig); +``` + +```js next.config.js +const { withPigment } = require('@pigment-css/nextjs-plugin'); + +const nextConfig = { + // ...Your nextjs config. +}; + +/** + * @type {import('@pigment-css/nextjs-plugin').PigmentOptions} + */ +const pigmentConfig = {}; // we will refer to this later + +module.exports = withPigment(nextConfig, pigmentConfig); +``` + + + +Finally, import the stylesheet at the top of the layout file. + +```js title="app/layout.(js|tsx)" +import '@pigment-css/react/styles.css'; +``` + +### Vite + +Install the Vite plugin as a dev dependency: + + + +```bash npm +npm install --save-dev @pigment-css/vite-plugin +``` + +```bash yarn +yarn add -D @pigment-css/vite-plugin +``` + +```bash pnpm +pnpm add -D @pigment-css/vite-plugin +``` + + + +Next, open vite config file, usually named `vite.config.js`, and add the plugin: + +```js +import { defineConfig } from 'vite'; +import { pigment } from '@pigment-css/vite-plugin'; + +const pigmentConfig = {}; // we will refer to this later + +export default defineConfig({ + plugins: [ + pigment(pigmentConfig), + // ... Your other plugins. + ], +}); +``` + +Finally, add the Pigment CSS stylesheet to the top of the main file. + +```js title="src/main.(js|tsx)" +import '@pigment-css/react/styles.css'; +``` + +## Configuring the theme + +Integrating Pigment CSS with Material UI requires you to configure the theme to the plugin. +Add the following code to your [Next.js](#nextjs) or [Vite](#vite) config file: + +```diff ++ import { extendTheme, stringifyTheme } from '@mui/material'; + ++ const customTheme = extendTheme(); ++ customTheme.toRuntimeSource = stringifyTheme; + ++ const pigmentConfig = { ++ theme: customTheme, ++ }; +``` + +If you don't have a custom theme, you are ready to go. Start a development server by running: + + + +```bash npm +npm run dev +``` + +```bash yarn +yarn dev +``` + +```bash pnpm +pnpm dev +``` + + + +Open the browser and navigate to the localhost URL, you should see the app running with Pigment CSS. + +## How it works + +When a Pigment CSS plugin is configured through a framework bundler, it intercepts the styling APIs that Material UI uses and replaces them with those from Pigment CSS instead. Pigment CSS then extracts the styles at build time and injects them into the stylesheet. + +If you come from Material UI v5, using Pigment CSS will be a paradigm shift in terms of writing styles. +Since Pigment CSS is a build-time extraction tool, it does not support dynamic styles that depend on the runtime variables, e.g. Pigment CSS will throw an error for the styles that depends on a state like the one below: + +```js +import Card from '@mui/material/Card'; + +function App() { + const [color, setColor] = useState('#000000'); + return ( + + ); +} +``` + +We recommend reading the rest of the guide below to learn about the new styling paradigm and patterns for creating dynamic styles. + +## Migrating custom theme + +### Removing owner state + +Since Pigment CSS is a build-time extraction tool, it does not support owner state through callbacks. Here is an example that will throw an error at build time: + +```js +const theme = extendTheme({ + components: { + MuiCard: { + styleOverrides: { + root: { + color: ({ ownerState }) => ({ + // ❌ Pigment CSS cannot extract this style. + ...(ownerState.variant === 'outlined' && { + borderWidth: 3, + }), + }), + }, + }, + }, + }, +}); +``` + +Run the following codemod to remove the owner state from the theme: + +```bash +npx @mui/codemod@next v6.0.0/theme-v6 next.config.mjs +``` + +There are cases that the codemod is not able to remove the owner state. In such cases, you have to manually replace the owner state with `variants`. + +#### Dynamic color based on palette + +If you have a dynamic color based on the theme palette, you can use the `variants` property to define the styles for each palette. + + + +```js before +const theme = extendTheme({ + components: { + MuiCard: { + styleOverrides: { + root: ({ theme, ownerState }) => ({ + color: theme.palette[ownerState.palette]?.main, + }), + }, + }, + }, +}); +``` + +```js after +const theme = extendTheme({ + components: { + MuiCard: { + styleOverrides: { + root: ({ theme }) => ({ + variants: [ + ...Object.entries(theme.palette) + .filter(([, palette]) => palette && palette.main) + .map(([palette, { main }]) => ({ + props: { palette }, + style: { + color: main, + }, + })), + ], + }), + }, + }, + }, +}); +``` + + + +### Default props provider + +Use `DefaultPropsProvider` in your main application file and move all the component default props to it: + + + +```diff next.config|vite.config + import { extendTheme } from '@mui/material'; + + const customTheme = extendTheme({ + // ...other tokens. + components: { + MuiButtonBase: { +- defaultProps: { +- disableRipple: true, +- }, + }, + MuiSelect: { +- defaultProps: { +- IconComponent: DropdownIcon, +- }, + } + } + }); +``` + +```diff App.tsx ++ import DefaultPropsProvider from '@mui/material/DefaultPropsProvider'; + + function App() { + return ( ++ + {/* Your app */} ++ + ); + } +``` + + + +## Migrating dynamic styles + +### sx prop + +Run the following codemod: + +```bash +npx @mui/codemod@next v6.0.0/sx-prop path/to/folder +``` + +The scenarios below are not covered by the codemod, you have to manually update them: + + + +#### Dynamic values + +If a value depends on a variable, you need to move it to a CSS variable inside inline styles. + + + +```js before +
+ {items.map((item, index) => ( + + ))} +
+``` + +```js after +
+ {items.map((item, index) => ( + + ))} +
+``` + +
+ +### styled + +If you have a custom components that are using `styled` from `@mui/material/styles`, change the import source to `@mui/material-pigment-css`: + +```diff +- import { styled } from '@mui/material/styles'; ++ import { styled } from '@mui/material-pigment-css'; +``` + +Then, run the following codemod: + +```bash +npx @mui/codemod@next v6.0.0/styled path/to/folder +``` + +The scenarios below are not covered by the codemod, you have to manually update them: + +#### Dynamic styles based on props + +If you have dynamic styles based on props, you need to move them to CSS variables. You will need to create a wrapper component to set the inline style with the CSS variables. + + + +```js before +const FlashCode = styled('div')( + ({ theme, startLine = 0, endLine = startLine, lineHeight = '0.75rem' }) => ({ + top: `calc(${lineHeight} * 1.5 * ${startLine})`, + height: `calc(${lineHeight} * 1.5 * ${endLine - startLine + 1})`, + ...theme.typography.caption, + }), +); + +export default FlashCode; +``` + +```js after +const FlashCodeRoot = styled('div')(({ theme }) => ({ + top: `calc(var(--Flashcode-lineHeight) * 1.5 * var(--Flashcode-startLine))`, + height: `calc(var(--Flashcode-lineHeight) * 1.5 * (var(--Flashcode-endLine) - var(--Flashcode-startLine) + 1))`, + ...theme.typography.caption, +})); + +const FlashCode = React.forwardRef(function FlashCode(props, ref) { + const { + children, + startLine = 0, + endLine = startLine, + lineHeight = '0.75rem', + ...other + } = props; + + return ( + + {children} + + ); +}); + +export default FlashCode; +``` + + + +## Migrating layout components + +To use layout components that are compatible with Pigment CSS, replace the following components with those from the adapter package: + +```diff +- import Container from '@mui/material/Container'; ++ import Container from '@mui/material-pigment-css/Container'; + +- import Grid from '@mui/material/Grid'; ++ import Grid from '@mui/material-pigment-css/Grid'; + +- import Stack from '@mui/material/Stack'; ++ import Stack from '@mui/material-pigment-css/Stack'; + +- import Hidden from '@mui/material/Hidden'; ++ import Hidden from '@mui/material-pigment-css/Hidden'; +``` + +## Migrating Box component + +Choose one of the following approaches: + +### Continue using Box component + +Replace the `Box` component with the one from the adapter package: + +```diff +- import Box from '@mui/material/Box'; ++ import Box from '@mui/material-pigment-css/Box'; +``` + +### Replace Box with HTML element + +Pigment CSS can extract the `sx` prop from any JSX element, so there is no need to use the Box component. + +```diff +- import Box from '@mui/material/Box'; + + function CustomCard() { + return ( +- +- +- ... +- ++
++ ++ ... ++
+ ) + } +``` + +For **TypeScript** users, you need to extend the `HTMLAttributes` interface to support the `sx` prop. Add the following code to a file that is included in your `tsconfig.json`: + +```ts +import type { Theme, SxProps } from '@mui/material/styles'; + +declare global { + namespace React { + interface HTMLAttributes { + sx?: SxProps; + } + } +} +``` diff --git a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md index de404b9a6cbcee..56a333d6fd3032 100644 --- a/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md +++ b/docs/data/material/migration/migrating-to-v6/migrating-to-v6.md @@ -347,6 +347,8 @@ This reduces the API surface and lets you define variants in other slots of the ## Pigment CSS integration (optional) -:::info -⏳ This section is under construction -::: +Pigment CSS lets you extract styles at build time, reducing the bundle size and avoiding client-side recalculation compared to Emotion/Styled-components. + +Pigment CSS can work alongside Emotion/Styled-components, allowing you to migrate gradually. + +Check out the [migrating to Pigment CSS guide](/material-ui/migration/migrating-to-pigment-css/) to learn more. diff --git a/docs/data/material/pages.ts b/docs/data/material/pages.ts index 37711a12ab4cb2..752c2b622b1879 100644 --- a/docs/data/material/pages.ts +++ b/docs/data/material/pages.ts @@ -283,6 +283,10 @@ const pages: MuiPage[] = [ pathname: '/material-ui/migration/migration-css-theme-variables', title: 'Migrating to CSS theme variables', }, + { + pathname: '/material-ui/migration/migrating-to-pigment-css', + title: 'Migrating to Pigment CSS', + }, ], }, { diff --git a/docs/pages/material-ui/migration/migrating-to-pigment-css.js b/docs/pages/material-ui/migration/migrating-to-pigment-css.js new file mode 100644 index 00000000000000..96725a1d9b5e82 --- /dev/null +++ b/docs/pages/material-ui/migration/migrating-to-pigment-css.js @@ -0,0 +1,7 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import * as pageProps from 'docs/data/material/migration/migrating-to-v6/migrating-to-pigment-css.md?muiMarkdown'; + +export default function Page() { + return ; +}