{"id":13494439,"url":"https://github.com/mui/pigment-css","last_synced_at":"2025-05-13T23:07:49.918Z","repository":{"id":232697359,"uuid":"715829513","full_name":"mui/pigment-css","owner":"mui","description":"Pigment CSS is a zero-runtime CSS-in-JS library that extracts the colocated styles to their own CSS files at build time.","archived":false,"fork":false,"pushed_at":"2024-10-25T11:37:20.000Z","size":1551,"stargazers_count":768,"open_issues_count":107,"forks_count":38,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-10-29T21:19:52.294Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mui.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":null,"patreon":null,"open_collective":"mui-org","ko_fi":null,"tidelift":null,"custom":null}},"created_at":"2023-11-07T23:12:26.000Z","updated_at":"2024-10-29T15:41:24.000Z","dependencies_parsed_at":"2024-11-07T20:20:36.538Z","dependency_job_id":"75a9976e-fef8-460d-9c9e-f7ad9e505bbd","html_url":"https://github.com/mui/pigment-css","commit_stats":{"total_commits":408,"total_committers":23,"mean_commits":17.73913043478261,"dds":0.7254901960784313,"last_synced_commit":"624e608d04b48c27fce9edf3ecf255081a22b370"},"previous_names":["mui/pigment-css","mui/zero-runtime"],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mui%2Fpigment-css","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mui%2Fpigment-css/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mui%2Fpigment-css/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mui%2Fpigment-css/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mui","download_url":"https://codeload.github.com/mui/pigment-css/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247451639,"owners_count":20940939,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T19:01:25.066Z","updated_at":"2025-04-10T17:16:09.580Z","avatar_url":"https://github.com/mui.png","language":"TypeScript","funding_links":["https://opencollective.com/mui-org"],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003c!-- markdownlint-disable-next-line --\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://mui.com/blog/introducing-pigment-css/\" target=\"_blank\"\u003e\n    \u003cpicture\u003e\n      \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://master--material-ui.netlify.app/static/pigment-css/pigment-css-logo-dark.svg\"\u003e\n      \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://master--material-ui.netlify.app/static/pigment-css/pigment-css-logo-light.svg\"\u003e\n      \u003cimg alt=\"Pigment CSS\" src=\"https://master--material-ui.netlify.app/static/pigment-css/pigment-css-logo-light.svg\" width=\"324\" height=\"57\"\u003e\n    \u003c/picture\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\nPigment CSS is a zero-runtime CSS-in-JS library that extracts the colocated styles to their own CSS files at build time.\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/mui/pigment-css/blob/HEAD/LICENSE)\n[![npm latest package](https://img.shields.io/npm/v/@pigment-css/react/latest.svg)](https://www.npmjs.com/package/@pigment-css/react)\n[![npm downloads](https://img.shields.io/npm/dm/@pigment-css/react.svg)](https://www.npmjs.com/package/@pigment-css/react)\n[![GitHub branch status](https://img.shields.io/github/checks-status/mui/pigment-css/HEAD)](https://app.codecov.io/gh/mui/pigment-css/tree/master)\n[![Coverage Status](https://img.shields.io/codecov/c/github/mui/pigment-css.svg)](https://app.codecov.io/gh/mui/pigment-css/)\n[![Follow on X](https://img.shields.io/twitter/follow/PigmentCSS.svg?label=follow+Pigment+CSS)](https://x.com/PigmentCSS)\n[![Renovate status](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://github.com/mui/pigment-css/issues/2)\n[![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/mui/pigment-css.svg)](https://isitmaintained.com/project/mui/pigment-css 'Average time to resolve an issue')\n[![Open Collective backers and sponsors](https://img.shields.io/opencollective/all/mui-org)](https://opencollective.com/mui-org)\n[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9161/badge)](https://www.bestpractices.dev/projects/9161)\n\n\u003c/div\u003e\n\n---\n\n# Documentation\n\n- [Getting started](#getting-started)\n  - [Why choose Pigment CSS](#why-choose-pigmentcss)\n  - [Start with Next.js](#start-with-nextjs)\n  - [Start with Vite](#start-with-vite)\n- [Basic usage](#basic-usage)\n  - [Creating styles](#creating-styles)\n  - [Creating components](#creating-components)\n    - [Styling based on props](#styling-based-on-props)\n    - [Styling based on runtime values](#styling-based-on-runtime-values)\n    - [Styled component as a CSS selector](#styled-component-as-a-css-selector)\n    - [Media and Container queries](#media-and-container-queries)\n    - [Typing props](#typing-props)\n  - [Creating animation keyframes](#creating-animation-keyframes)\n  - [Creating global styles](#creating-global-styles)\n- [Theming](#theming)\n  - [Accessing theme values](#accessing-theme-values)\n  - [CSS variables support](#css-variables-support)\n  - [Adding a prefix to CSS variables](#adding-a-prefix-to-css-variables)\n  - [Color schemes](#color-schemes)\n  - [Switching color schemes](#switching-color-schemes)\n  - [Styling based on color scheme](#styling-based-on-color-scheme)\n  - [TypeScript](#typescript)\n- [sx prop](#sx-prop)\n- [Right-to-left support](#right-to-left-support)\n- [How-to guides](#how-to-guides)\n  - [Coming from Emotion or styled-components](#coming-from-emotion-or-styled-components)\n- [Building reusable components for UI libraries](#building-reusable-components-for-ui-libraries)\n- [How Pigment CSS works](#how-pigmentcss-works)\n\n## Getting started\n\nPigment CSS supports Next.js and Vite with support for more bundlers in the future.\nYou must install the corresponding plugin, as shown below.\n\n### Why choose Pigment CSS\n\nThanks to recent advancements in CSS (like CSS variables and `color-mix()`), \"traditional\" CSS-in-JS solutions that process styles at runtime are no longer required for unlocking features like color transformations and theme variables which are necessary for maintaining a sophisticated design system.\n\nPigment CSS addresses the needs of the modern React developer by providing a zero-runtime CSS-in-JS styling solution as a successor to tools like Emotion and styled-components.\n\nCompared to its predecessors, Pigment CSS offers improved DX and runtime performance (though at the cost of increased build time) while also being compatible with React Server Components.\nPigment CSS is built on top of [WyW-in-JS](https://wyw-in-js.dev/), enabling to provide the smoothest possible experience for Material UI users when migrating from Emotion in v5 to Pigment CSS in v6.\n\n### Start with Next.js\n\n#### Quickstart\n\nUse the following commands to quickly create a new Next.js project with Pigment CSS set up:\n\n```bash\ncurl https://codeload.github.com/mui/pigment-css/tar.gz/master | tar -xz --strip=2  pigment-css-master/examples/pigment-css-nextjs-ts\ncd pigment-css-nextjs-ts\n```\n\n#### Manual installation\n\n```bash\nnpm install @pigment-css/react\nnpm install --save-dev @pigment-css/nextjs-plugin\n```\n\nThen, in your `next.config.js` file, import the plugin and wrap the exported config object:\n\n```js\nimport { withPigment } from '@pigment-css/nextjs-plugin';\n\nexport default withPigment({\n  // ... Your nextjs config.\n});\n```\n\nFinally, import the stylesheet in the root `layout.tsx` file:\n\n```diff\n import type { Metadata } from 'next';\n+import '@pigment-css/react/styles.css';\n\n export const metadata: Metadata = {\n   title: 'Create Next App',\n   description: 'Generated by create next app',\n };\n\n export default function RootLayout(props: { children: React.ReactNode }) {\n   return (\n     \u003chtml lang=\"en\"\u003e\n       \u003cbody\u003e{props.children}\u003c/body\u003e\n     \u003c/html\u003e\n   );\n }\n```\n\n### Start with Vite\n\n#### Quickstart\n\nUse the following commands to quickly create a new Vite project with Pigment CSS set up:\n\n```bash\ncurl https://codeload.github.com/mui/pigment-css/tar.gz/master | tar -xz --strip=2 pigment-css-master/examples/pigment-css-vite-ts\ncd pigment-css-vite-ts\n```\n\n#### Manual installation\n\n```bash\nnpm install @pigment-css/react\nnpm install --save-dev @pigment-css/vite-plugin\n```\n\nThen, in your Vite config file, import the plugin and pass it to the `plugins` array as shown:\n\n```js\nimport { pigment } from '@pigment-css/vite-plugin';\n\nexport default defineConfig({\n  plugins: [\n    pigment(),\n    // ... Your other plugins.\n  ],\n});\n```\n\nFinally, import the stylesheet in the root `main.tsx` file:\n\n```diff\n import * as React from 'react';\n import { createRoot } from 'react-dom/client';\n+import '@pigment-css/react/styles.css';\n import App from './App';\n\n const rootElement = document.getElementById('root');\n const root = createRoot(rootElement);\n\n root.render(\n   \u003cReact.StrictMode\u003e\n     \u003cApp /\u003e\n   \u003c/React.StrictMode\u003e,\n );\n```\n\n## Basic usage\n\n**You must configure Pigment CSS with [Next.js](#nextjs) or [Vite](#vite) first.**\n\n### Creating styles\n\nUse the `css` API to create reusable styles:\n\n```js\nimport { css } from '@pigment-css/react';\n\nconst visuallyHidden = css({\n  border: 0,\n  clip: 'rect(0 0 0 0)',\n  height: '1px',\n  margin: -1,\n  overflow: 'hidden',\n  padding: 0,\n  position: 'absolute',\n  whiteSpace: 'nowrap',\n  width: '1px',\n});\n\nfunction App() {\n  return \u003cdiv className={visuallyHidden}\u003eI am invisible\u003c/div\u003e;\n}\n```\n\nThe call to the `css` function is replaced with a unique string that represents the CSS class name for the generated styles.\n\nUse a callback function to get access to the [theme](#theming) values:\n\n```js\nconst title = css(({ theme }) =\u003e ({\n  color: theme.colors.primary,\n  fontSize: theme.spacing.unit * 4,\n  fontFamily: theme.typography.fontFamily,\n}));\n```\n\n### Creating components\n\nUse the `styled` API to create a component by passing styles at the end. The usage should be familiar if you've worked with Emotion or styled-components:\n\n```js\nimport { styled } from '@pigment-css/react';\n\nconst Heading = styled('div')({\n  fontSize: '4rem',\n  fontWeight: 'bold',\n  padding: '10px 0px',\n});\n\nfunction App() {\n  return \u003cHeading\u003eHello\u003c/Heading\u003e;\n}\n```\n\nPigment CSS differs from \"standard\" runtime CSS-in-JS libraries in a few ways:\n\n1. You never get direct access to props in your styled declarations. This is because prop values are only available at runtime, but the CSS is extracted at build time. See [Styling based on runtime values](#styling-based-on-runtime-values) for a workaround.\n2. Your styles must be declarative and must account for all combinations of props that you want to style.\n3. The theme lets you declare CSS tokens that become part of the CSS bundle after the build. Any other values and methods that it might have are only available during build time—not at runtime. This leads to smaller bundle sizes.\n\n#### Styling based on props\n\n\u003e 💡 This approach is recommended when the value of the prop is known at build time (finite values).\n\nUse the `variants` key to define styles for a combination of the component's props.\n\nEach variant is an object with `props` and `style` keys. The styles are applied when the component's props match the `props` object.\n\n**Example 1** — A button component with `small` and `large` sizes:\n\n```tsx\ninterface ButtonProps {\n  size?: 'small' | 'large';\n}\n\nconst Button = styled('button')\u003cButtonProps\u003e({\n  border: 'none',\n  padding: '0.75rem',\n  // ...other styles\n  variants: [\n    {\n      props: { size: 'large' },\n      style: { padding: '1rem' },\n    },\n    {\n      props: { size: 'small' },\n      style: { padding: '0.5rem' },\n    },\n  ],\n});\n\n\u003cButton\u003eNormal button\u003c/Button\u003e; // padding: 0.75rem\n\u003cButton size=\"large\"\u003eLarge button\u003c/Button\u003e; // padding: 1rem\n\u003cButton size=\"small\"\u003eSmall button\u003c/Button\u003e; // padding: 0.5rem\n```\n\n**Example 2** — A button component with variants and colors:\n\n```jsx\nconst Button = styled('button')({\n  border: 'none',\n  padding: '0.75rem',\n  // ...other base styles\n  variants: [\n    {\n      props: { variant: 'contained', color: 'primary' },\n      style: { backgroundColor: 'tomato', color: 'white' },\n    },\n  ],\n});\n\n// `backgroundColor: 'tomato', color: 'white'`\n\u003cButton variant=\"contained\" color=\"primary\"\u003e\n  Submit\n\u003c/Button\u003e;\n```\n\n**Example 3** — Apply styles based on a condition:\n\nThe value of the `props` can be a function that returns a boolean. If the function returns `true`, the styles are applied.\n\n```jsx\nconst Button = styled('button')({\n  border: 'none',\n  padding: '0.75rem',\n  // ...other base styles\n  variants: [\n    {\n      props: (props) =\u003e props.variant !== 'contained',\n      style: { backgroundColor: 'transparent' },\n    },\n  ],\n});\n```\n\nNote that the `props` function doesn't work if it is inside another closure, for example, inside an `array.map`:\n\n```jsx\nconst Button = styled('button')({\n  border: 'none',\n  padding: '0.75rem',\n  // ...other base styles\n  variants: ['red', 'blue', 'green'].map((item) =\u003e ({\n    props: (props) =\u003e {\n      // ❌ Cannot access `item` in this closure\n      return props.color === item \u0026\u0026 !props.disabled;\n    },\n    style: { backgroundColor: 'tomato' },\n  })),\n});\n```\n\nInstead, use plain objects to define the variants:\n\n```jsx\nconst Button = styled('button')({\n  border: 'none',\n  padding: '0.75rem',\n  // ...other base styles\n  variants: ['red', 'blue', 'green'].map((item) =\u003e ({\n    props: { color: item, disabled: false },\n    style: { backgroundColor: 'tomato' },\n  })),\n});\n```\n\n#### Styling based on runtime values\n\n\u003e 💡 This approach is recommended when the value of a prop is **unknown** ahead of time or possibly unlimited values, for example styling based on the user's input.\n\nThere are two ways to achieve this (both involve using a CSS variable):\n\n1. Declare a CSS variable directly in the styles and set its value using inline styles:\n\n   ```jsx\n   const Heading = styled('h1')({\n     color: 'var(--color)',\n   });\n\n   function Heading() {\n     const [color, setColor] = React.useState('red');\n\n     return \u003cHeading style={{ '--color': color }} /\u003e;\n   }\n   ```\n\n2. Use a callback function as a value to create a dynamic style for the specific CSS property:\n\n   ```jsx\n   const Heading = styled('h1')({\n     color: ({ isError }) =\u003e (isError ? 'red' : 'black'),\n   });\n   ```\n\n   Pigment CSS replaces the callback with a CSS variable and injects the value through inline styles. This makes it possible to create a static CSS file while still allowing dynamic styles.\n\n   ```css\n   .Heading_class_akjsdfb {\n     color: var(--Heading_class_akjsdfb-0);\n   }\n   ```\n\n   ```jsx\n   \u003ch1\n     style={{\n       '--Heading_class_akjsdfb-0': isError ? 'red' : 'black',\n     }}\n   \u003e\n     Hello\n   \u003c/h1\u003e\n   ```\n\n#### Styled component as a CSS selector\n\nAll of the components that you create are also available as CSS selectors. For example, for the `Heading` component described in the previous section, you can target that component inside another styled component like this:\n\n```jsx\nconst Wrapper = styled.div({\n  [`\u0026 ${Heading}`]: {\n    color: 'blue',\n  },\n});\n```\n\nThis enables you to override the default `color` of the Heading component rendered inside the Wrapper:\n\n```tsx\n\u003cWrapper\u003e\n  \u003cHeading\u003eHello\u003c/Heading\u003e\n\u003c/Wrapper\u003e\n```\n\nYou can also export any styled component you create and use it as the base for additional components:\n\n```jsx\nconst ExtraHeading = styled(Heading)({\n  // ... overridden styled\n});\n```\n\n#### Media and Container queries\n\nPigment CSS APIs have built-in support for writing media queries and container queries. Use the `@media` and `@container` keys to define styles for different screen and container sizes.\n\n```jsx\nimport { css, styled } from '@pigment-css/react';\n\nconst styles = css({\n  fontSize: '2rem',\n  '@media (min-width: 768px)': {\n    fontSize: '3rem',\n  },\n  '@container (max-width: 768px)': {\n    fontSize: '1.5rem',\n  },\n});\n\nconst Heading = styled('h1')({\n  fontSize: '2rem',\n  '@media (min-width: 768px)': {\n    fontSize: '3rem',\n  },\n  '@container (max-width: 768px)': {\n    fontSize: '1.5rem',\n  },\n});\n```\n\n\u003e 💡 **Good to know**:\n\u003e\n\u003e Pigment CSS uses Emotion behind the scenes for turning tagged templates and objects into CSS strings.\n\n#### Typing props\n\nIf you use TypeScript, add the props typing before the styles to get the type checking:\n\n```tsx\nconst Heading = styled('h1')\u003c{ isError?: boolean }\u003e({\n  color: ({ isError }) =\u003e (isError ? 'red' : 'black'),\n});\n```\n\n### Creating animation keyframes\n\nUse the `keyframes` API to create reusable [animation keyframes](https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes):\n\n```js\nimport { keyframes } from '@pigment-css/react';\n\nconst fadeIn = keyframes`\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n`;\n\nfunction Example1() {\n  return \u003cdiv style={{ animation: `${fadeIn} 0.5s` }}\u003eI am invisible\u003c/div\u003e;\n}\n```\n\nThe call to the `keyframes` function is replaced with a unique string that represents the CSS animation name. It can be used with `css` or `styled` too.\n\n```js\nimport { css, styled, keyframes } from '@pigment-css/react';\n\nconst fadeIn = keyframes(...);\n\nconst Example2 = styled('div')({\n  animation: `${fadeIn} 0.5s`,\n});\n\nfunction App() {\n  return (\n    \u003c\u003e\n      \u003cExample1 /\u003e\n      \u003cdiv\n        className={css`\n          animation: ${fadeIn} 0.5s;\n        `}\n      /\u003e\n    \u003c/\u003e\n  )\n}\n```\n\n### Creating global styles\n\nUse the `globalCss` API to create global styles:\n\n```js\nimport { globalCss } from '@pigment-css/react';\n\nglobalCss`\n  body {\n    margin: 0;\n    padding: 0;\n  }\n`;\n```\n\nThe `globalCss` function should to be called at the top level of your JavaScript file, usually from the entry point of the application.\n\nCalling inside a function or a component will not work as expected. Also, the extraction of global styles will always take place regardless of conditional rendering.\n\n## Theming\n\nTheming is an **optional** feature that lets you reuse the same values, such as colors, spacing, and typography, across your application. It is a plain object of any structure that you can define in your config file.\n\n\u003e **💡 Good to know**:\n\u003e\n\u003e The **theme** object is used at build time and does not exist in the final JavaScript bundle. This means that components created using Pigment CSS's `styled` can be used with React Server Components by default while still getting the benefits of theming.\n\nFor example, in Next.js, you can define a theme in the `next.config.js` file like this:\n\n```js\nimport { withPigment } from '@pigment-css/nextjs-plugin';\n\nexport default withPigment(\n  {\n    // ...other nextConfig\n  },\n  {\n    theme: {\n      colors: {\n        primary: 'tomato',\n        secondary: 'cyan',\n      },\n      spacing: {\n        unit: 8,\n      },\n      typography: {\n        fontFamily: 'Inter, sans-serif',\n      },\n      // ...more keys and values, it's free style!\n    },\n  },\n);\n```\n\n### Accessing theme values\n\nA callback can be used with **styled()** and **css()** APIs to access the theme values:\n\n```js\nconst Heading = styled('h1')(({ theme }) =\u003e ({\n  color: theme.colors.primary,\n  fontSize: theme.spacing.unit * 4,\n  fontFamily: theme.typography.fontFamily,\n}));\n```\n\n### CSS variables support\n\nPigment CSS can generate CSS variables from the theme values when you wrap your theme with `extendTheme` utility. For example, in a `next.config.mjs` file:\n\n```js\nimport { withPigment, extendTheme } from '@pigment-css/nextjs-plugin';\n\nexport default withPigment(\n  {\n    // ...nextConfig\n  },\n  {\n    theme: extendTheme({\n      colors: {\n        primary: 'tomato',\n        secondary: 'cyan',\n      },\n      spacing: {\n        unit: 8,\n      },\n      typography: {\n        fontFamily: 'Inter, sans-serif',\n      },\n    }),\n  },\n);\n```\n\nThe `extendTheme` utility goes through the theme and creates a `vars` object which represents the tokens that refer to CSS variables.\n\n```jsx\nconst theme = extendTheme({\n  colors: {\n    primary: 'tomato',\n    secondary: 'cyan',\n  },\n});\n\nconsole.log(theme.colors.primary); // 'tomato'\nconsole.log(theme.vars.colors.primary); // 'var(--colors-primary)'\n```\n\n### Adding a prefix to CSS variables\n\nYou can add a prefix to the generated CSS variables by providing a `cssVarPrefix` option to the `extendTheme` utility:\n\n```jsx\nextendTheme({\n  cssVarPrefix: 'pigment',\n});\n```\n\nThe generated CSS variables have the `pigment` prefix:\n\n```css\n:root {\n  --pigment-colors-background: #f9f9f9;\n  --pigment-colors-foreground: #121212;\n}\n```\n\n### Color schemes\n\nSome tokens, especially color-related tokens, can have different values for different scenarios. For example in a daylight condition, the background color might be white, but in a dark condition, it might be black.\n\nThe `extendTheme` utility lets you define a theme with a special `colorSchemes` key:\n\n```jsx\nextendTheme({\n  colorSchemes: {\n    light: {\n      colors: {\n        background: '#f9f9f9',\n        foreground: '#121212',\n      },\n    },\n    dark: {\n      colors: {\n        background: '#212121',\n        foreground: '#fff',\n      },\n    },\n  },\n});\n```\n\nIn the above example, `light` (default) and `dark` color schemes are defined. The structure of each color scheme must be a plain object with keys and values.\n\n### Switching color schemes\n\nBy default, when `colorSchemes` is defined, Pigment CSS uses the [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) media query to switch between color schemes based on the user's system settings.\n\nHowever, if you want to control the color scheme based on application logic, for example, using a button to switch between light and dark mode, you can customize the behavior by providing a `getSelector` function:\n\n```diff\n extendTheme({\n   colorSchemes: {\n     light: { ... },\n     dark: { ... },\n   },\n+  getSelector: (colorScheme) =\u003e colorScheme ? `.theme-${colorScheme}` : ':root',\n });\n```\n\nNote that you need to add the logic to a button by yourself. Here is an example of how to do it:\n\n```jsx\nfunction App() {\n  return (\n    \u003cbutton\n      onClick={() =\u003e {\n        document.documentElement.classList.toggle('theme-dark');\n      }}\n    \u003e\n      Toggle color scheme\n    \u003c/button\u003e\n  );\n}\n```\n\n### Styling based on color scheme\n\nThe `extendTheme` utility attaches a function called `applyStyles` to the theme object. It receives a color scheme as the first argument followed by a style object.\nIt returns a proper CSS selector based on the theme configuration.\n\n```jsx\nconst Heading = styled('h1')(({ theme }) =\u003e ({\n  color: theme.colors.primary,\n  fontSize: theme.spacing.unit * 4,\n  fontFamily: theme.typography.fontFamily,\n  ...theme.applyStyles('dark', {\n    color: theme.colors.primaryLight,\n  }),\n}));\n```\n\n### TypeScript\n\nTo get the type checking for the theme, you need to augment the theme type:\n\n```ts\n// any file that is included in your tsconfig.json\nimport type { ExtendTheme } from '@pigment-css/react/theme';\n\ndeclare module '@pigment-css/react/theme' {\n  interface ThemeTokens {\n    // the structure of your theme\n  }\n\n  interface ThemeArgs {\n    theme: ExtendTheme\u003c{\n      colorScheme: 'light' | 'dark';\n      tokens: ThemeTokens;\n    }\u003e;\n  }\n}\n```\n\n## sx prop\n\nA special `sx` prop lets you apply styles directly to an element. When `sx` prop is specified on an element, Pigment CSS will replace it with `className` and `style` props at build time.\n\nThe `sx` prop works on any element, including HTML elements and 3rd-party custom components as long as it is JSX.\n\n### Usage\n\n```js\n\u003cdiv sx={{ display: 'flex', flexDirection: 'column' }}\u003e\n```\n\nFor a React component like the example below, it must pass the `className` and `style` props to the underlying DOM element, otherwise the styles won't be applied.\n\n```js\n// /path/to/AnyComponent.js\nconst AnyComponent = (props) =\u003e {\n  return \u003cdiv {...props} /\u003e;\n};\n\n// /path/to/App.js\n\u003cAnyComponent sx={{ fontSize: 12, color: 'red' }} /\u003e;\n```\n\nThe value provided to `sx` prop can be one of the following:\n\n- a plain style object (recommended for best performance)\n- a callback function that receives the [theme object](#theming) then return a plain style object:\n\n  ```js\n  \u003cdiv sx={(theme) =\u003e ({ color: theme.colors.primary })} /\u003e\n  ```\n\n- an array of plain style objects or callback functions. This is useful for applying conditional styles based on other variables:\n\n  ```js\n  \u003cdiv\n    sx={[\n      { color: 'red' },\n      selected \u0026\u0026 { fontWeight: 'bold' },\n      disabled ? (theme) =\u003e ({ opacity: theme.state.disabledOpacity }) : { opacity: 1 },\n    ]}\n  /\u003e\n  ```\n\n### TypeScript\n\nTo use `sx` prop on HTML element, you need to augment the `HTMLAttributes` interface. Add the following code to a file that is included in your tsconfig.json:\n\n```ts\ntype Theme = {\n  // your theme type\n};\n\ndeclare global {\n  namespace React {\n    interface HTMLAttributes\u003cT\u003e {\n      sx?:\n        | React.CSSProperties\n        | ((theme: Theme) =\u003e React.CSSProperties)\n        | ReadonlyArray\u003cReact.CSSProperties | ((theme: Theme) =\u003e React.CSSProperties)\u003e;\n    }\n  }\n}\n```\n\n## Right-to-left support\n\nTo support right-to-left (RTL) languages, add the `dir=\"rtl\"` attribute to your app's `\u003chtml\u003e` element or any other equivalent top level container. Then, update your bundler config as follows to generate styles for both directions:\n\n### Next.js\n\n```js\nimport { withPigment } from '@pigment-css/nextjs-plugin';\n\n// ...\nexport default withPigment(nextConfig, {\n  theme: yourCustomTheme,\n  // CSS output option\n  css: {\n    // Specify your default CSS authoring direction\n    defaultDirection: 'ltr',\n    // Generate CSS for the opposite of the `defaultDirection`\n    // This is set to `false` by default\n    generateForBothDir: true,\n  },\n});\n```\n\n### Vite\n\n```js\nimport { pigment } from '@pigment-css/vite-plugin';\n\nexport default defineConfig({\n  plugins: [\n    pigment({\n      theme: yourTheme,\n      css: {\n        // Specify your default CSS authoring direction\n        defaultDirection: 'ltr',\n        // Generate CSS for the opposite of the `defaultDirection`\n        // This is set to `false` by default\n        generateForBothDir: true,\n      },\n    }),\n    // ... other plugins.\n  ],\n});\n```\n\n### Generated CSS\n\nFor example, if you've specified `defaultDirection: 'ltr'` and `dir=\"rtl\"`, and your authored CSS looks like this:\n\n```js\nimport { css } from '@pigment-css/react';\n\nconst className = css`\n  margin-left: 10px,\n  margin-right: 20px,\n  padding: '0 10px 20px 30px'\n`;\n```\n\nThen the actual CSS output would be:\n\n```css\n.cmip3v5 {\n  margin-left: 10px;\n  margin-right: 20px;\n  padding: 0 10px 20px 30px;\n}\n\n[dir='rtl'] .cmip3v5 {\n  margin-right: 10px;\n  margin-left: 20px;\n  padding: 0 30px 20px 10px;\n}\n```\n\n### Custom dir selector\n\nThe default selector in the output CSS is `[dir=rtl]` or `[dir=ltr]`. You can customize it by passing an optional `getDirSelector` method to the `css` property in your bundler config:\n\n```js\n    css: {\n      getDirSelector(dir: string) {\n        // return a custom selector you'd like to use\n        return `:dir(${dir})`;\n      },\n    },\n```\n\n## How-to guides\n\n### Coming from Emotion or styled-components\n\nEmotion and styled-components are runtime CSS-in-JS libraries. What you write in your styles is what you get in the final bundle, which means the styles can be as dynamic as you want with bundle size and performance overhead trade-offs.\n\nOn the other hand, Pigment CSS extracts CSS at build time and replaces the JavaScript code with hashed class names and some CSS variables. This means that it has to know all of the styles to be extracted ahead of time, so there are rules and limitations that you need to be aware of when using JavaScript callbacks or variables in Pigment CSS's APIs.\n\nHere are some common patterns and how to achieve them with Pigment CSS:\n\n#### 1. Fixed set of styles\n\nIn Emotion or styled-components, you can use props to create styles conditionally:\n\n```js\nconst Flex = styled('div')((props) =\u003e ({\n  display: 'flex',\n  ...(props.vertical // ❌ Pigment CSS will throw an error\n    ? {\n        flexDirection: 'column',\n        paddingBlock: '1rem',\n      }\n    : {\n        paddingInline: '1rem',\n      }),\n}));\n```\n\nBut in Pigment CSS, you need to define all of the styles ahead of time using the `variants` key:\n\n```js\nconst Flex = styled('div')((props) =\u003e ({\n  display: 'flex',\n  variants: [\n    {\n      props: { vertical: true },\n      style: {\n        flexDirection: 'column',\n        paddingBlock: '1rem',\n      },\n    },\n    {\n      props: { vertical: false },\n      style: {\n        paddingInline: '1rem',\n      },\n    },\n  ],\n}));\n```\n\n\u003e 💡 Keep in mind that the `variants` key is for fixed values of props, for example, a component's colors, sizes, and states.\n\n#### 2. Programatically generated styles\n\nFor Emotion and styled-components, the styles are different on each render and instance because the styles are generated at runtime:\n\n```js\nfunction randomBetween(min: number, max: number) {\n  return Math.floor(Math.random() * (max - min + 1) + min);\n}\nfunction generateBubbleVars() {\n  return `\n    --x: ${randomBetween(10, 90)}%;\n    --y: ${randomBetween(15, 85)}%;\n  `;\n}\n\nfunction App() {\n  return (\n    \u003cdiv\u003e\n      {[...Array(10)].map((_, index) =\u003e (\n        \u003cdiv key={index} className={css`${generateBubbleVars()}`} /\u003e\n      ))}\n    \u003c/div\u003e\n  )\n}\n```\n\nHowever, in Pigment CSS with the same code as above, all instances have the same styles and won't change between renders because the styles are extracted at build time.\n\nTo achieve the same result, you need to move the dynamic logic to props and pass the value to CSS variables instead:\n\n```js\nfunction randomBetween(min: number, max: number) {\n  return Math.floor(Math.random() * (max - min + 1) + min);\n}\n\nconst Bubble = styled('div')({\n  '--x': props =\u003e props.x,\n  '--y': props =\u003e props.y,\n});\n\nfunction App() {\n  return (\n    \u003cdiv\u003e\n      {[...Array(10)].map((_, index) =\u003e (\n        \u003cBubble key={index} x={`${randomBetween(10, 90)}%`} y={`${randomBetween(15, 85)}%`} /\u003e\n      ))}\n    \u003c/div\u003e\n  )\n}\n```\n\n## Building reusable components for UI libraries\n\nThe purpose of this guide is to demonstrate how to create reusable components for a UI library that can be shared across multiple projects and used to implement different design systems through custom theming.\nThe approach outlined here is not necessary when constructing components to be consumed and themed in a single project.\nIt's most relevant for developers who want to build a component library that could be published as a package to be consumed and themed by other developers.\n\nThe steps below will walk you through how to create a statistics component that could serve as part of a reusable UI library built with Pigment CSS.\nThis process has three parts:\n\n1. [Create component slots](#1-create-component-slots).\n2. [Compose slots to create the component](#2-create-the-component).\n3. [Style slots based on props](#3-style-slots-based-on-props).\n\n### 1. Create component slots\n\nSlots let the consumers customize each individual element of the component by targeting its respective name in the [theme's styleOverrides](#themeable-statistics-component).\n\nThis statistics component is composed of three slots:\n\n- `root`: the container of the component\n- `value`: the number to be displayed\n- `unit`: the unit or description of the value\n\n\u003e 💡 Though you can give these slots any names you prefer, we recommend using `root` for the outermost container element for consistency with the rest of the library.\n\nUse the `styled` API with `name` and `slot` parameters to create the slots, as shown below:\n\n```js\n// /path/to/Stat.js\nimport * as React from 'react';\nimport { styled } from '@pigment-css/react';\n\nconst StatRoot = styled('div', {\n  name: 'PigmentStat', // The component name\n  slot: 'root', // The slot name\n})({\n  display: 'flex',\n  flexDirection: 'column',\n  gap: '1rem',\n  padding: '0.75rem 1rem',\n  backgroundColor: '#f9f9f9',\n  borderRadius: '8px',\n  boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',\n  letterSpacing: '-0.025em',\n  fontWeight: 600,\n});\n\nconst StatValue = styled('div', {\n  name: 'PigmentStat',\n  slot: 'value',\n})({\n  font: '1.2rem \"Fira Sans\", sans-serif',\n});\n\nconst StatUnit = styled('div', {\n  name: 'PigmentStat',\n  slot: 'unit',\n})({\n  font: '0.875rem \"Fira Sans\", sans-serif',\n  color: '#121212',\n});\n```\n\n### 2. Create the component\n\nAssemble the component using the slots created in the previous step:\n\n```js\n// /path/to/Stat.js\nimport * as React from 'react';\n\n// ...slot styled-components\n\nconst Stat = React.forwardRef(function Stat(props, ref) {\n  const { value, unit, ...other } = props;\n\n  return (\n    \u003cStatRoot ref={ref} {...other}\u003e\n      \u003cStatValue\u003e{value}\u003c/StatValue\u003e\n      \u003cStatUnit\u003e{unit}\u003c/StatUnit\u003e\n    \u003c/StatRoot\u003e\n  );\n});\n\nexport default Stat;\n```\n\n### 3. Style slots based on props\n\nIn this example, a prop named `variant` is defined to let consumers change the appearance of the `Stat` component.\n\nPass down the `variant` prop to `\u003cStatRoot\u003e` to style the `root` slot, as shown below:\n\n```diff\n const Stat = React.forwardRef(function Stat(props, ref) {\n+  const { value, unit, variant, ...other } = props;\n\n   return (\n-     \u003cStatRoot ref={ref} {...other}\u003e\n-       \u003cStatValue\u003e{value}\u003c/StatValue\u003e\n-       \u003cStatUnit\u003e{unit}\u003c/StatUnit\u003e\n-     \u003c/StatRoot\u003e\n+     \u003cStatRoot ref={ref} variant={variant} {...other}\u003e\n+       \u003cStatValue\u003e{value}\u003c/StatValue\u003e\n+       \u003cStatUnit\u003e{unit}\u003c/StatUnit\u003e\n+     \u003c/StatRoot\u003e\n   );\n });\n```\n\nThen you can use Pigment CSS variants API to style it when `variant` prop has a value of `outlined`:\n\n```diff\n const StatRoot = styled('div', {\n   name: 'PigmentStat',\n   slot: 'root',\n })({\n   display: 'flex',\n   flexDirection: 'column',\n   gap: '1rem',\n   padding: '0.75rem 1rem',\n   backgroundColor: '#f9f9f9',\n   borderRadius: '8px',\n   boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',\n   letterSpacing: '-0.025em',\n   fontWeight: 600,\n+  variants: [\n+    {\n+      props: { variant: 'outlined' },\n+      style: {\n+        border: `2px solid #e9e9e9`,\n+      },\n+    },\n+  ],\n });\n```\n\nThis completes the reusable statistics component.\nIf this were a real UI library, the component would be ready to upload to a package registry so others could use it.\n\n### Consumer usage\n\nDevelopers using your component must first install your package as well as the Pigment CSS packages that correspond to the [framework](#start-with-nextjs) they're using.\n\n```bash\nnpm install your-package-name @pigment-css/react\nnpm install -D @pigment-css/nextjs-plugin\n```\n\nNext, they must set up Pigment CSS in their project:\n\n```js\n// framework config file, for example next.config.js\nimport { withPigment } from '@pigment-css/nextjs-plugin';\n\nexport default withPigment(\n  {\n    // ... Your nextjs config.\n  },\n  { transformLibraries: ['your-package-name'] },\n);\n```\n\nFinally, they must import the stylesheet in the root layout file:\n\n```js\n// index.tsx\nimport '@pigment-css/react/styles.css';\n```\n\nThen they can use your component in their project:\n\n```jsx\nimport Stat from 'your-package-name/Stat';\n\nfunction App() {\n  return \u003cStat value={42} unit=\"km/h\" variant=\"outlined\" /\u003e;\n}\n```\n\n### Consumer theming\n\nDevelopers can customize the component's styles using the theme's `styleOverrides` key and the component name and slots you defined in [step 2](#2-create-the-component).\nFor example, the custom theme below sets the background color of the statistics component's root slot to `tomato`:\n\n```js\nexport default withPigment(\n  { ...nextConfig },\n  {\n    theme: {\n      components: {\n        PigmentStat: {\n          styleOverrides: {\n            root: {\n              backgroundColor: 'tomato',\n            },\n            value: {\n              color: 'white',\n            },\n            unit: {\n              color: 'white',\n            },\n          },\n        },\n      },\n    },\n  },\n);\n```\n\nDevelopers can also access theme values and apply styles based on the component's props using the `variants` key:\n\n```js\nexport default withPigment(\n  { ...nextConfig },\n  {\n    theme: {\n      // user defined colors\n      colors: {\n        primary: 'tomato',\n        primaryLight: 'lightcoral',\n      },\n      components: {\n        PigmentStat: {\n          styleOverrides: {\n            root: ({ theme }) =\u003e ({\n              backgroundColor: 'tomato',\n              variants: [\n                {\n                  props: { variant: 'outlined' },\n                  style: {\n                    border: `2px solid ${theme.colors.primary}`,\n                    backgroundColor: theme.colors.primaryLight,\n                  },\n                },\n              ],\n            }),\n            value: {\n              color: 'white',\n            },\n            unit: {\n              color: 'white',\n            },\n          },\n        },\n      },\n    },\n  },\n);\n```\n\n## How Pigment CSS works\n\nSee [How Pigment CSS works](HOW_PIGMENT_CSS_WORKS.md) for details on the build process.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmui%2Fpigment-css","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmui%2Fpigment-css","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmui%2Fpigment-css/lists"}