# Panda CSS Complete Documentation > Panda CSS is a CSS-in-JS framework with build-time optimizations for styling web applications This document contains the complete Panda CSS documentation, organized by category for easy navigation. ## Table of Contents ### Styling - [Agent Skills](#agent-skills) - [Using Angular](#using-angular) - [Using Astro](#using-astro) - [Browser Support](#browser-support) - [Cascade Layers](#cascade-layers) - [Migrating from Chakra UI](#migrating-from-chakra-ui) - [Panda CLI](#panda-cli) - [Color opacity modifier](#color-opacity-modifier) - [The compiler engine](#the-compiler-engine) - [Conditional Styles](#conditional-styles) - [Dynamic styling](#dynamic-styling) - [Using Ember](#using-ember) - [Migrating from Emotion](#migrating-from-emotion) - [The extend keyword](#the-extend-keyword) - [Frequently Asked Questions](#frequently-asked-questions) - [Using Gatsby](#using-gatsby) - [Welcome to Panda](#welcome-to-panda) - [Global Styles](#global-styles) - [How Panda works](#how-panda-works) - [Installation](#installation) - [JSX Style Context](#jsx-style-context) - [LLMs.txt](#llms.txt) - [MCP Server](#mcp-server) - [Merging Styles](#merging-styles) - [Migration strategy](#migration-strategy) - [Using Next.js](#using-next.js) - [Using Nuxt](#using-nuxt) - [Patterns](#patterns) - [Performance & Optimization](#performance-&-optimization) - [Using PostCSS](#using-postcss) - [Using Preact](#using-preact) - [Using Qwik](#using-qwik) - [Using React Router](#using-react-router) - [Recipes](#recipes) - [Using Redwood](#using-redwood) - [Using Remix](#using-remix) - [Responsive Design](#responsive-design) - [Using Rsbuild](#using-rsbuild) - [Slot Recipes](#slot-recipes) - [Using SolidJS](#using-solidjs) - [Migrating from Stitches](#migrating-from-stitches) - [Using Storybook](#using-storybook) - [Style props](#style-props) - [Migrating from Styled Components](#migrating-from-styled-components) - [Styled System](#styled-system) - [Migrating from StyleX](#migrating-from-stylex) - [Using Svelte](#using-svelte) - [Migrating from Tailwind CSS](#migrating-from-tailwind-css) - [Template Literals](#template-literals) - [Migrating from Theme UI](#migrating-from-theme-ui) - [Thinking in Panda](#thinking-in-panda) - [Upgrading to v2](#upgrading-to-v2) - [viewTransition()](#viewtransition()) - [Virtual Color](#virtual-color) - [Using Vite](#using-vite) - [Using Vue](#using-vue) - [Writing Styles](#writing-styles) ### Theming - [Animation Styles](#animation-styles) - [Custom Font](#custom-font) - [Layer Styles](#layer-styles) - [Multi-Theme Tokens](#multi-theme-tokens) - [Spec](#spec) - [Using Panda Studio](#using-panda-studio) - [Panda Studio in v2](#panda-studio-in-v2) - [Text Styles](#text-styles) - [Theme](#theme) - [Tokens](#tokens) - [Using Tokens](#using-tokens) ### Design Systems - [Avoiding CSS collisions](#avoiding-css-collisions) - [Build a design system](#build-a-design-system) - [Conditions](#conditions) - [Config Functions](#config-functions) - [Consume a design system](#consume-a-design-system) - [Ecosystem plugins](#ecosystem-plugins) - [Environment-specific config](#environment-specific-config) - [Federated Micro-Frontends](#federated-micro-frontends) - [forwardProps](#forwardprops) - [Panda Integration Hooks](#panda-integration-hooks) - [Isolated declarations](#isolated-declarations) - [Minimal Setup](#minimal-setup) - [Monorepo dev workflow](#monorepo-dev-workflow) - [Using Panda in a Component Library](#using-panda-in-a-component-library) - [Customizing Patterns](#customizing-patterns) - [Building a design system with Panda](#building-a-design-system-with-panda) - [Presets](#presets) - [Publishing to npm](#publishing-to-npm) - [Set up a library package](#set-up-a-library-package) - [Shared styled-system in a monorepo](#shared-styled-system-in-a-monorepo) - [Ship the styled-system vs the CSS](#ship-the-styled-system-vs-the-css) - [Static CSS Generator](#static-css-generator) - [Track usage in wrapped components](#track-usage-in-wrapped-components) - [Troubleshooting](#troubleshooting) - [Utilities](#utilities) - [Wrap headless UI](#wrap-headless-ui) ### Reference - [Background](#background) - [Border](#border) - [CLI Reference](#cli-reference) - [Configuring Panda](#configuring-panda) - [Debugging](#debugging) - [Deprecations](#deprecations) - [Diagnostics Reference](#diagnostics-reference) - [Display](#display) - [Divide](#divide) - [Editor & IDE tooling](#editor-&-ide-tooling) - [Effects](#effects) - [ESLint & OXLint Plugin](#eslint-&-oxlint-plugin) - [Flex and Grid](#flex-and-grid) - [Focus Ring](#focus-ring) - [Gradients](#gradients) - [Helpers](#helpers) - [Interactivity](#interactivity) - [Layout](#layout) - [List](#list) - [Masks](#masks) - [Outline](#outline) - [Sizing](#sizing) - [Spacing](#spacing) - [SVG](#svg) - [Tables](#tables) - [Transforms](#transforms) - [Transitions](#transitions) - [Typography](#typography) --- # Styling ## Agent Skills Portable, job-shaped skill packs that teach AI coding agents how to use Panda correctly. Agent Skills are coming soon and aren't published yet, so treat the shape below as a preview. For AI agent support that works today, see [LLMs.txt](/docs/styling/llms-txt) and [MCP Server](/docs/styling/mcp-server). ## The problem it's meant to solve AI coding agents are a normal part of how Panda projects get written today, but without something grounding them, agents commonly reach for the wrong instincts: emitting Tailwind class strings or Emotion-style patterns in a Panda project, inventing raw hex or spacing values instead of using tokens, or wiring a design system by hand (`include: ['…/panda.buildinfo.json']`) instead of the newer dedicated mechanism. Community skill packs for Panda exist today but are thin and unofficial, while some other libraries already ship official ones. ## How this differs from LLMs.txt and MCP Panda already has two other AI-facing mechanisms, and Agent Skills is meant to be a third, distinct one, not a replacement for either: - **[LLMs.txt](/docs/styling/llms-txt)** hands an agent the documentation itself, a static content dump for context. - **[MCP Server](/docs/styling/mcp-server)** answers "what exists right now" in your specific project, live token, recipe, and pattern lookups. - **Agent Skills** would answer "how do I do this correctly," procedural, decision-oriented guidance (which API to reach for, what not to do), read once per task rather than queried live. ## The planned skills Rather than one large reference document, the plan is six small, job-shaped skills, so an agent loads only the one relevant to the task in front of it: | Skill | Job | | --- | --- | | `panda-styling` | Write or edit styles in application or component code | | `panda-recipes` | Build or change recipes, slot recipes, or `cva`/`sva` | | `panda-tokens` | Author or extend theme tokens and conditions | | `panda-setup` | Install, initialize, and wire up a build tool | | `panda-design-system` | Publish or consume a design system | | `panda-migrate-v2` | Upgrade from v1, or navigate a v2 beta | Each skill is planned to stay short (roughly 200 to 300 lines), lead with when an agent should reach for it, and include short do/don't examples rather than long prose, along the lines of what [skills.sh](https://skills.sh/) already hosts for other libraries. ## Installing skills (once published) The install experience is expected to follow the same shape as any other package on the open skills ecosystem: ```bash npx skills add /@panda-styling ``` Where exactly Panda's skills will be published from (the main repo, or a dedicated skills-only repo) isn't finalized, so treat the exact install path above as illustrative rather than a real command to run today. ## See also - [LLMs.txt](/docs/styling/llms-txt) and [MCP Server](/docs/styling/mcp-server) for the AI-facing tooling that exists today. - [Upgrading to v2](/docs/styling/upgrading-to-v2) for the broader context this feature is part of. --- ## Using Angular Easily use Panda with Angular with our dedicated integration. This guide shows you how to set up Panda CSS in an Angular project using PostCSS. ## Start a new project ### Create Vite project To get started, we will need to create a new Angular project using the official [scaffolding tool](https://angular.dev/tools/cli). If you don't enter any parameter, the CLI will guide you through the process of creating a new Angular app. ```bash ng new test-app ``` You will be asked a few questions, answer them as follows: ```bash ? Which stylesheet format would you like to use? CSS ? Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No ``` ### Install Panda Install panda and create your `panda.config.ts` file. {/* */} ```bash pnpm install -D @pandacss/dev pnpm panda init ``` ```bash npm install -D @pandacss/dev npx panda init ``` ```bash yarn add -D @pandacss/dev yarn panda init ``` ```bash bun add -D @pandacss/dev bun panda init ``` {/* */} ### Configure PostCSS Create a `postcss.config.json` file in the root of your project and add the following code: ```json filename="postcss.config.json" { "plugins": { "@pandacss/dev/postcss": {} } } ``` > You must use a JSON file for the PostCSS configuration, as the Angular CLI does not support JavaScript PostCSS > configuration files. ### Update package.json scripts Open your `package.json` file and update the `scripts` section as follows: ```diff {3} filename="package.json" { "scripts": { + "prepare": "panda codegen", "ng": "ng", "start": "ng serve", "build": "ng build", } } ``` - `"prepare"` - script that will run Panda CSS CLI codegen before each build. Read more about [codegen](/docs/reference/cli#codegen) in the CLI section. > This step ensures that the panda output directory is regenerated after each dependency installation. So you can add > the output directory to your `.gitignore` file and not worry about it. ### Configure the content Make sure that all of the paths of your Angular components are included in the `include` section of the `panda.config.ts` file. ```js {8,17} filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ // Whether to use css reset preflight: true, // Where to look for your css declarations include: ['./src/**/*.{js,jsx,ts,tsx}'], // Files to exclude exclude: [], // The output directory for your css system outdir: 'styled-system' }) ``` ### Configure the entry CSS with layers Add this code to an `src/index.css` file and import it in the root component of your project. ```css filename="src/index.css" @layer reset, base, tokens, recipes, utilities; ``` ## Start your build process Run the following command to start your development server. {/* */} ```bash pnpm dev ``` ```bash npm run dev ``` ```bash yarn dev ``` ```bash bun dev ``` {/* */} ### Start using Panda Now you can start using Panda CSS in your project. Here is the snippet of code that you can use in your `src/app.component.ts` file. ```typescript filename="src/app.component.ts" import { Component } from '@angular/core' import { css } from '../styled-system/css' @Component({ selector: 'app-root', standalone: true, template: `
` }) export class App { redBg = css({ bg: 'red.400' }) } ```
--- ## Using Astro Easily use Panda with Astro with our dedicated integration. This guide shows you how to set up Panda CSS in an Astro project using our dedicated integration. ## Setup ### Install Panda Install panda and create your `panda.config.ts` file. {/* */} ```bash pnpm install -D @pandacss/dev pnpm panda init --postcss ``` ```bash npm install -D @pandacss/dev npx panda init --postcss ``` ```bash yarn add -D @pandacss/dev yarn panda init --postcss ``` ```bash bun add -D @pandacss/dev bun panda init --postcss ``` {/* */} ### Update package.json scripts Open your `package.json` file and update the `scripts` section as follows: ```diff {3} { "scripts": { + "prepare": "panda codegen", "dev": "astro dev", "start": "astro start", "build": "astro build", "preview": "astro preview" } } ``` The `prepare` script that will run codegen after dependency installation. Read more about [codegen](/docs/reference/cli#codegen) in the CLI section. > This step ensures that the panda output directory is regenerated after each dependency installation. So you can add > the output directory to your `.gitignore` file and not worry about it. ### Configure the content Add your panda config to your `panda.config.js` file, or wherever panda is configured in your project. ```js {6} import { defineConfig } from '@pandacss/dev' export default defineConfig({ preflight: true, // define the content to scan πŸ‘‡πŸ» include: ['./src/**/*.{ts,tsx,js,jsx,astro}', './pages/**/*.{ts,tsx,js,jsx,astro}'], exclude: [], outdir: 'styled-system' }) ``` ### Configure the entry CSS with layers Add the layer css code to the `src/index.css` file ```css filename="src/index.css" @layer reset, base, tokens, recipes, utilities; ``` Then, import the `src/index.css` file in your page or layout file ```md filename="src/pages/index.astro" --- import '../index.css'; --- ``` ### Update the postcss config Astro requires a little change for the `postcss.config.cjs` that `panda init --postcss` generated: ```diff {3} filename="postcss.config.cjs" module.exports = { - plugins: { - '@pandacss/dev/postcss': {} - } + plugins: [require('@pandacss/dev/postcss')()] } ``` ### Start your build process Run your build process with `npm run dev` or whatever command is configured in your package.json file. {/* */} ```bash pnpm dev ``` ```bash npm run dev ``` ```bash yarn dev ``` ```bash bun dev ``` {/* */} ### Start using Panda Use the generated style utilities in your code, and panda will extract them to the generated CSS file. ```jsx --- import { css } from '../../styled-system/css'; ---
Hello !
```
## Troubleshooting If you're not getting import autocomplete in your IDE, you may need to include the `styled-system` directory in your `tsconfig.json` file: ```json filename="tsconfig.json" { // ... "include": ["src", "styled-system"] } ``` --- ## Browser Support Learn about the browser support for Panda Panda CSS is built with modern CSS features and uses [PostCSS](https://postcss.org/) to add support for older browsers. Panda supports the latest, stable releases of major browsers that support the following features: - [CSS Variables](https://caniuse.com/css-variables) - [CSS Cascade Layers](https://caniuse.com/css-cascade-layers) - Modern selectors, such as [`:where()`](https://caniuse.com/mdn-css_selectors_where) and [`:is()`](https://caniuse.com/css-matches-pseudo) ## Browserlist Based on the above criteria, the following browsers are supported: ```txt >= 1% last 1 major version not dead Chrome >= 99 Edge >= 99 Firefox >= 97 iOS >= 15.4 Safari >= 15.4 Android >= 115 Opera >= 73 ``` ## Polyfills For older browsers: - Set `polyfill: true` (or `--polyfill`) so Panda emits cascade-layer order without `@layer` (see [Cascade Layers](/docs/concepts/cascade-layers#polyfills)). - Add [autoprefixer](https://github.com/postcss/autoprefixer) in PostCSS when you need vendor prefixes. ```js // postcss.config.cjs module.exports = { plugins: ['@pandacss/dev/postcss', 'autoprefixer'] } ``` --- ## Cascade Layers CSS cascade layers refer to the order in which CSS rules are applied to an HTML element. When multiple CSS rules apply to the same element, the browser uses the cascade to determine which rule should take precedence. See the [MDN article](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer) to learn more. Panda takes advantage of the cascade to provide a more efficient and flexible way to organize styles. This allows you to define styles in a modular way, using CSS rules that are scoped to specific components or elements. ## Layer Types Panda supports five types of cascade layers out of the box: - `@layer reset` - The reset layer is used to reset the default styles of HTML elements. This is used when `preflight: true` is set in the config. You can also use this layer to add your own reset styles. The generated CSS for the reset layer looks like this: ```css @layer reset { * { box-sizing: border-box; margin: 0; padding: 0; } /* ... */ } ``` - `@layer base` - The base layer contains global styles defined in the `globalStyles` key in the config. You can also use this layer to add your own global styles. The generated CSS for the base layer looks like this: ```css @layer base { a { color: #000; text-decoration: none; } /* ... */ } ``` - `@layer recipes` - The recipes layer contains styles for recipes created within the config (aka config recipes). You can also use this layer to add your own component styles. The generated CSS for the recipes layer looks like this: ```css @layer recipes { .button { /* ... */ } .button--variant-primary { /* ... */ } /* ... */ } ``` - `@layer tokens` - The tokens layer contains css variables for tokens and semantic tokens. You can also use this layer to add your own design tokens. The generated CSS for the tokens layer looks like this: ```css @layer tokens { :root { --color-primary: #000; --color-secondary: #fff; --color-tertiary: #ccc; --shadow-sm: 0 0 0 1px rgba(0, 0, 0, 0.05); } /* ... */ } ``` - `@layer utilities` - Styles that are scoped to a specific utility class. These styles are only applied to elements that have the utility class applied. ## Layer Order The cascade layers are applied in the following order: - `@layer utilities` (Highest priority) - `@layer recipes` - `@layer tokens` - `@layer base` - `@layer reset` (Lowest priority) This means that styles defined in the `@layer utilities` will take precedence over styles defined in the `@layer recipes`. This is useful when you want to override the default styles of a component. ## Layer CSS The generated CSS in Panda is organized into layers. This allows you to define styles in a modular way, using CSS rules that are scoped to specific components or elements. Here's what the first line of the generated CSS looks like: ```css @layer reset, base, tokens, recipes, utilities; ``` Adding this line to the top of your CSS file will determine the order in which the layers are applied. This is the most exciting feature of CSS cascade layers. ## Customize layers Panda lets you customize the cascade layers, so your project can coexist with other solutions. Learn more about customizing layers [here](/docs/reference/config#layers). ## Polyfills Need older browsers, or want unlayered CSS unable to override Panda? Turn on the built-in polyfill: ```js export default defineConfig({ // ... polyfill: true }) ``` Or pass `--polyfill` to `panda` / `panda cssgen`. Emit replaces `@layer` with `:not(#\#)` specificity boosts (same idea as `@csstools/postcss-cascade-layers`). Keep `@layer reset, base, …;` in your entry CSS so PostCSS / Vite / webpack can find the stylesheet root β€” hosts strip that Panda order line when polyfill is on. --- ## Migrating from Chakra UI Migrate your project from Chakra UI to Panda and see how style props, theme, and variants map across. This guide outlines the steps needed to migrate your project from Chakra UI to Panda and highlights key design differences between the two. > **Note:** Chakra's own team has said its theming system was deliberately designed to align with Panda's > conventions, `globalCss`, `{ value }`-wrapped tokens, and `recipes`/`slotRecipes` terminology all match Panda > directly, while Chakra still runs on Emotion at runtime rather than Panda's static extraction. Several of the > mappings below will already look familiar because of that. Here are some similarities between the two: - Both support style props directly on components, and both support design tokens defined in a central theme. - Both support responsive values and a similar breakpoint-object shorthand. - Both have a first-class idea of a component "variant" that's more than just a class name toggle. Here's where they differ. ## Performance Chakra styles components with `@emotion/styled` at runtime: every style prop and `sx` value is computed by Emotion in the browser (or on the server during SSR), and the CSS is injected on the fly. Panda extracts your style objects at build time and ships plain static CSS, there's no runtime style computation cost at all. This matters most in large component trees or lists, where Chakra's runtime style computation happens per render. ## Theming Chakra builds a system with `createSystem` and a config from `defineConfig`, then passes it to `ChakraProvider` as `value`: ```jsx import { ChakraProvider, createSystem, defaultConfig, defineConfig } from '@chakra-ui/react' const config = defineConfig({ theme: { tokens: { colors: { brand: { value: '#0ea5e9' } } } } }) const system = createSystem(defaultConfig, config) export default function App({ children }) { return {children} } ``` Notice the token shape, `{ value: '#0ea5e9' }`, is the same wrapper Panda uses. Panda doesn't need a provider, the theme lives in `panda.config.ts` and is resolved at build time, not read from React context at render time: ```ts filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ theme: { extend: { tokens: { colors: { brand: { value: '#0ea5e9' } } } } } }) ``` See [Tokens](/docs/theming/tokens) for the full token model. ## The `sx` prop Chakra's `sx` prop (and the lower-priority `__css` prop) layers ad hoc styles onto a component that already has style props: ```jsx ``` Panda's closest equivalent is the `css` prop on the `styled` factory, or just building the class name directly with `css()`: ```jsx import { styled } from '../styled-system/jsx' ``` ```jsx import { css } from '../styled-system/css'
``` See [JSX Style Props](/docs/styling/style-props) for the full set of ways to style a component inline. ## Variants Chakra defines a component's variants with `defineRecipe` (single-part) or `defineSlotRecipe` (multi-part, like `Menu` or `Tabs`), registered on the system's `theme.recipes`/`theme.slotRecipes`: ```ts import { defineRecipe } from '@chakra-ui/react' export const buttonRecipe = defineRecipe({ base: { fontWeight: 'bold' }, variants: { variant: { solid: { bg: 'brand', color: 'white' } } } }) ``` ```ts const config = defineConfig({ theme: { recipes: { button: buttonRecipe } } }) ``` Panda's equivalent is a [recipe](/docs/styling/recipes), either colocated with `cva`/`sva` or shared globally via `theme.recipes`/`theme.slotRecipes` in `panda.config.ts`, the same `base`/`variants` shape Chakra uses: ```ts filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ theme: { extend: { recipes: { button: { className: 'button', base: { fontWeight: 'bold' }, variants: { variant: { solid: { bg: 'brand.500', color: 'white' } } } } } } } }) ``` ```jsx import { button } from '../styled-system/recipes' ``` See [Recipes](/docs/styling/recipes) and [Slot Recipes](/docs/styling/slot-recipes). ## Color Modes Chakra's own docs recommend semantic tokens (`bg="bg.subtle"`, values that resolve automatically per color mode) as the preferred pattern, the same model Panda uses. A `useColorModeValue` hook is also available, opt-in via a CLI-generated snippet (`npx @chakra-ui/cli snippet add color-mode`) built on `next-themes`, for cases where a value genuinely needs to branch per color mode at the call site rather than through a token: ```jsx import { useColorModeValue } from '@/components/ui/color-mode' const bg = useColorModeValue('white', 'gray.800') ``` Panda defines the light/dark pair once, as a semantic token, and every user of that token gets the right value automatically, no hook call needed at the usage site: ```ts filename="panda.config.ts" theme: { extend: { semanticTokens: { colors: { bg: { value: { base: '{colors.white}', _dark: '{colors.gray.800}' } } } } } } ``` ```jsx
``` See [Theme](/docs/theming/theme) and [Multiple Themes](/docs/theming/multiple-themes) for semantic tokens and color-mode setup in depth. ## Global Styles Chakra applies global styles through the `globalCss` key in `defineConfig`, the same key name Panda uses: ```ts const config = defineConfig({ globalCss: { body: { bg: 'gray.50', color: 'gray.800' } } }) ``` Panda's version is the same shape, `globalCss` in `panda.config.ts`, no provider needed since it's emitted straight into the generated CSS: ```ts filename="panda.config.ts" export default defineConfig({ globalCss: { body: { bg: 'gray.50', color: 'gray.800' } } }) ``` See [Global Styles](/docs/styling/global-styles). ## Component Styles Chakra ships pre-styled components (`Box`, `Flex`, `Grid`, `Stack`) that accept style props directly: ```jsx import { Box, Grid } from '@chakra-ui/react' Box ``` Panda's [patterns](/docs/styling/patterns) cover the same layout primitives, as a JSX component or a plain function: ```jsx import { Box, Grid } from '../styled-system/jsx' Box ``` Panda doesn't ship interactive components (`Menu`, `Modal`, `Tabs`) the way Chakra does, since Panda is a styling engine, not a component library. If you need Chakra's interactive components without Chakra's runtime styling, see [Building a design system with Panda](/docs/design-systems/preset-overview) and consider a headless library like Ark UI on top of Panda instead, the same pattern covered in [Wrap headless UI](/docs/design-systems/wrap-headless-ui). ## Conclusion Chakra and Panda agree on a lot of the underlying concepts, matching config shapes (`globalCss`, `{ value }` tokens), matching recipe terminology, and semantic tokens as the preferred color-mode pattern on both sides, since Chakra's theming system was deliberately designed toward Panda's conventions. The real migration cost is mechanical: moving each of those concepts off Chakra's runtime (`ChakraProvider`, `createSystem`, the recipe hooks) onto Panda's build-time equivalent, and separately deciding what to do about Chakra's interactive components if you were relying on them. ## See also - [Migration strategy](/docs/styling/migration-strategy) for running both libraries side by side during the migration. - [Wrap headless UI](/docs/design-systems/wrap-headless-ui) if you need Chakra-like interactive components without Chakra's runtime. --- ## Panda CLI An alternative way to use Panda is by running the Panda CLI tool. This guide shows you how to use Panda as an alternative approach by running the Panda CLI tool. ### Install Panda {/* */} ```bash pnpm install -D @pandacss/dev pnpm panda init ``` ```bash npm install -D @pandacss/dev npx panda init ``` ```bash yarn add -D @pandacss/dev yarn panda init ``` ```bash bun add -D @pandacss/dev bun panda init ``` {/* */} ### Configure the content Add the paths to all of your JavaScript or TypeScript code where you intend to use panda. ```js {5} import { defineConfig } from '@pandacss/dev' export default defineConfig({ preflight: true, include: ['./src/**/*.{ts,tsx,js,jsx}', './pages/**/*.{ts,tsx,js,jsx}'], exclude: [], outdir: 'styled-system' }) ``` ### Update package.json scripts Open your `package.json` file and update the `scripts` section as follows: ```diff {3} { "scripts": { + "prepare": "panda codegen", } } ``` The `prepare` script that will run codegen after dependency installation. Read more about [codegen](/docs/reference/cli#codegen) in the CLI section. > This step ensures that the panda output directory is regenerated after each dependency installation. So you can add > the output directory to your `.gitignore` file and not worry about it. ### Import the generated CSS For each Panda run, it emits the generated CSS at the `styled-system/styles.css` file path. Import this file at the root component of your project. ```jsx {1} import './styled-system/styles.css' export function App() { return
Page
} ``` ### Start the Panda build process Run the CLI tool to scan your JavaScript and TypeScript files for style properties and call expressions. {/* */} ```bash # Run it once pnpm panda # Run it in watch mode pnpm panda --watch ``` ```bash # Run it once npx panda # Run it in watch mode npx panda --watch ``` ```bash # Run it once yarn panda # Run it in watch mode yarn panda --watch ``` ```bash # Run it once bun panda # Run it in watch mode bun panda --watch ``` {/* */} ### Start using Panda Use the generated style utilities in your code and panda will extract them to the generated CSS file. Then run your build process. ```jsx import { css } from './styled-system/css' export function App() { return
} ``` ## Troubleshooting If you're not getting import autocomplete in your IDE, you may need to include the `styled-system` directory in your `tsconfig.json` file: ```json filename="tsconfig.json" { // ... "include": ["src", "styled-system"] } ``` --- ## Color opacity modifier Append /{opacity} to color tokens so Panda emits color-mix; omit it for plain token references. Append `/{opacity}` to a color token, for example `red.300/40`, `{colors.black/50}`, or `red/half`. Panda emits [`color-mix`](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix) only when the suffix is present; plain values like `white` stay as token references. Works on color-connected utilities from `@pandacss/preset-base`: `background`, `color`, `borderColor`, and others. Browsers without `color-mix` use the solid token. ## Examples ### Basic example ```ts css({ bg: 'red.300/40', color: 'white' }) ``` ```css @layer utilities { .bg_red\.300\/40 { --mix-background: color-mix(in srgb, var(--colors-red-300) 40%, transparent); background: var(--mix-background, var(--colors-red-300)); } .text_white { color: var(--colors-white); } } ``` ### Using a custom property For `--*` variables in `css()`, wrap the token path in curly braces and reference it with `var()`: ```ts css({ '--overlay': '{colors.black/50}', bg: 'var(--overlay)' }) ``` ```ts // ❌ Not resolved '--overlay': 'colors.black/50' // βœ… Resolved to color-mix '--overlay': '{colors.black/50}' ``` ### Usage with virtual colors See [virtual colors](/docs/styling/virtual-color) for the full `colorPalette` API: ```ts css({ colorPalette: 'blue', '--tint': '{colors.colorPalette.500/50}', bg: 'var(--tint)' }) ``` ## Usage in custom utilities Support `{color}/{opacity}` on your own utilities through the `colorMix` helper on `utils`: ```ts export default defineConfig({ utilities: { background: { shorthand: 'bg', className: 'bg', values: 'colors', transform(value, args) { const mix = args.utils.colorMix(value) if (mix.invalid) return { background: value } return { background: mix.value } } } } }) ``` ### Using createColorMixTransform ```ts import type { PropertyTransform } from '@pandacss/types' export const createColorMixTransform = (prop: string): PropertyTransform => (value, args) => { const mix = args.utils.colorMix(value) if (mix.invalid) return { [prop]: value } const cssVar = '--mix-' + prop return { [cssVar]: mix.value, [prop]: `var(${cssVar}, ${mix.color})` } } ``` ```ts export default defineConfig({ utilities: { background: { shorthand: 'bg', className: 'bg', values: 'colors', transform: createColorMixTransform('background') } } }) ``` --- ## The compiler engine How Panda compiles your styles β€” a Rust engine built on Oxc, exposed to both Node and the browser. Panda's compiler is a Rust engine built on [Oxc](https://oxc.rs). It reads your source, pulls out the styles, and emits atomic CSS in cascade layers β€” the same model [How Panda works](/docs/styling/how-panda-works) describes, running on native code. If you're coming from an earlier version, the pipeline is what changed: ``` before ts-morph walks a TypeScript AST β†’ PostCSS generates the CSS after Oxc parses each file once β†’ native Rust emits the CSS ``` Your styles and your output don't change (see [Upgrading to v2](/docs/styling/upgrading-to-v2) for the handful of deliberate CSS differences). The machine underneath does. ## Two bindings, one engine The engine is a set of Rust crates. Two bindings wrap it, so the same code runs in both places: - **`@pandacss/compiler`** β€” a native binding (NAPI). The CLI and the Vite, webpack, and Rollup plugins use it. - **`@pandacss/compiler-wasm`** β€” the same engine compiled to WASM, for the browser. The playground and editor tooling run on it. Both talk to a filesystem trait rather than `node:fs` directly, which is what lets the engine compile to WASM at all. Node and browser builds produce the same CSS. ## One long-lived compiler The entry point is `createCompiler(config)`. It returns a stateful compiler you hold onto, not a one-shot function. The expensive work β€” turning your config into utilities, conditions, recipes, and a resolved token dictionary β€” happens once, when you create the compiler. The same instance is reused for every file you parse and every rebuild. You feed it files as they change (`parseFile`, `parseFiles`, `parseFileSource`) and ask it for CSS; the config isn't recompiled each time. That's what makes `panda dev` cheap: the watcher re-parses only the files that changed and re-emits, against config state that's already in memory. ## The pipeline: extract, encode, emit Data flows one way. Each stage is a separate crate, and dependencies point in the direction of the arrows β€” nothing downstream reaches back up. ``` source β†’ extract β†’ encode β†’ emit β†’ CSS ``` - **Extract.** Oxc parses each source file once and matches your style calls β€” `css()`, `cva()`, patterns, JSX style props, and the rest. One parse per file, no TypeScript program in the hot path. Static values (including local `const`s and imports from other files) are folded here. - **Encode.** Matched usage becomes atomic style records β€” one property/value/condition per atom, deduplicated. - **Emit.** Atoms, recipes, and your static CSS become real CSS rules, grouped into `@layer`s and written natively. No PostCSS pass. Codegen runs alongside this to write the `styled-system` output β€” the types and helpers you import. A faΓ§ade crate owns the multi-file build and watch state and wires the stages together; it's the single entry point both bindings talk to. ## What you gain You write the same Panda β€” static analysis of your source, atomic CSS, cascade layers, tokens, recipes, conditions. The compiled engine changes what that costs: - One parse per file, and no `ts-morph` AST to build and hold. - A smaller install, since the `ts-morph` / `ts-evaluator` dependency tree is gone. - One shared compiler core behind the tooling. Diagnostics and lint read the same extraction the build does, rather than reimplementing it β€” see [Diagnostics](/docs/reference/diagnostics), the [ESLint & oxlint plugin](/docs/reference/eslint-oxlint-plugin), and [Editor & IDE tooling](/docs/reference/editor-tooling). ## Still open: CSS optimization The emitter writes CSS natively and minifies when you set `minify: true`, but full parity with LightningCSS minification is still open. If you rely on the last few percent of that minified output, check the result before you ship it. ## See also - [How Panda works](/docs/styling/how-panda-works) for the extraction model this runs. - [Upgrading to v2](/docs/styling/upgrading-to-v2) for what else changes. --- ## Conditional Styles Learn how to use conditional and responsive styles in Panda. When writing styles, you might need to apply specific changes depending on a specific condition, whether it's based on breakpoint, css pseudo state, media query or custom data attributes. Panda allows you to write conditional styles, and provides common condition shortcuts to make your life easier. Let's say you want to change the background color of a button when it's hovered. You can do it like this: ```jsx ``` ## Overview ### Property based condition This works great, but might be a bit verbose. You can apply the condition `_hover` directly to the `bg` property, leading to a more concise syntax: ```diff ``` > Note: The `base` key is used to define the default value of the property, without any condition. ### Nested condition Conditions in Panda can be nested, which means you can apply multiple conditions to a single property or another condition. Let's say you want to change the background color of a button when it's focused and hovered. You can do it like this: ```jsx ``` ### Built-in conditions Panda includes a set of common pseudo states that you can use to style your components: - Pseudo Class: `_hover`, `_active`, `_focus`, `_focusVisible`, `_focusWithin`, `_disabled` - Pseudo Element: `_before`, `_after` - Media Query: `sm`, `md`, `lg`, `xl`, `2xl` - Data Attribute Selector: `_horizontal`, `_vertical`, `_portrait`, `_landscape` ## Arbitrary selectors What if you need a one-off selector that is not defined in your config's conditions? You can use the `css` function to generate classes for arbitrary selectors: ```tsx import { css } from '../styled-system/css' const App = () => { return (
*': { margin: '2' } })} /> ) } ``` This also works with the supported at-rules (`@media`, `@layer`, `@container`, `@supports`, and `@page`): ```tsx import { css } from '../styled-system/css' const App = () => { return (
) } ``` ## Pseudo Classes ### Hover, Active, Focus, and Disabled You can style the hover, active, focus, and disabled states of an element using their `_` modifier: ```jsx ``` ### First, Last, Odd, Even You can style the first, last, odd, and even elements of a group using their `_` modifier: ```jsx
    {items.map(item => (
  • {item}
  • ))}
``` You can also style even and odd elements using the `_even` and `_odd` modifier: ```jsx {items.map(item => ( ))}
{item}
``` ## Pseudo Elements ### Before and After You can style the `::before` and `::after` pseudo elements of an element using their `_before` and `_after` modifier: ```jsx
Hello
``` #### Notes - **Before and After**: Ensure you wrap the content value in double quotes. - **Mixing with Conditions**: When using condition and pseudo elements, prefer to place the condition **before** the pseudo element. ```jsx css({ // This works βœ… _dark: { _backdrop: { color: 'red' } } // This doesn't work ❌ _backdrop: { _dark: { color: 'red' } } }) ``` The reason `_backdrop: { _dark: { color: 'red' } }` doesn't work is because it generated an invalid CSS structure that looks like: ```css &::backdrop { &.dark, .dark & { color: red; } } ``` ### Placeholder Style the placeholder text of any input or textarea using the `_placeholder` modifier: ```jsx ``` ### File Inputs Style the file input button using the `_file` modifier: ```jsx ``` ## Media Queries ### Reduced Motion Use the `_motionReduce` and `_motionSafe` modifiers to style an element based on the user's motion preference: ```jsx
Hello
``` ### Color Scheme The `prefers-color-scheme` media feature is used to detect if the user has requested the system use a light or dark color theme. Use the `_osLight` and `_osDark` modifiers to style an element based on the user's color scheme preference: ```jsx
Hello
``` Let's say your app is dark by default, but you want to allow users to switch to a light theme. You can do it like this: ```jsx
Hello
``` ### Color Contrast The `prefers-contrast` media feature is used to detect if the user has requested the system use a high or low contrast theme. Use the `_highContrast` and `_lessContrast` modifiers to style an element based on the user's color contrast preference: ```jsx
Hello
``` ### Orientation The `orientation` media feature is used to detect if the user has a device in portrait or landscape mode. Use the `_portrait` and `_landscape` modifiers to style an element based on the user's device orientation: ```jsx
Hello
``` ## Group Selectors When you need to style an element based on its parent element's state or attribute, you can add the `group` class to the parent element, and use any of the `_group*` modifiers on the child element. ```jsx

Hover me

``` This modifer for every pseudo class modifiers like `_groupHover`, `_groupActive`, `_groupFocus`, and `_groupDisabled`, etc. ## Sibling Selectors When you need to style an element based on its sibling element's state or attribute, you can add the `peer` class to the sibling element, and use any of the `_peer*` modifiers on the target element. ```jsx

Hover me

I'll change by bg

``` > Note: This only works for when the element marked with `peer` is a previous siblings, that is, it comes before the > element you want to start. ## Data Attribute ### LTR and RTL You can style an element based on the direction of the text using the `_ltr` and `_rtl` modifiers: ```jsx
Hello
``` For this to work, you need to set the `dir` attribute on the parent element. In most cases,you can set this on the `html` element. > **Note:** Consider using logical css properties like `marginInlineStart` and `marginInlineEnd` instead their physical > counterparts like `marginLeft` and `marginRight`. This will reduce the need to use the `_ltr` and `_rtl` modifiers. ### State You can style an element based on its `data-{state}` attribute using the corresponding `_{state}` modifier: ```jsx
Hello
``` This also works for common states like `data-active`, `data-disabled`, `data-focus`, `data-hover`, `data-invalid`, `data-required`, and `data-valid`. ```jsx
Hello
``` > Most of the `data-{state}` attributes typically mirror the corresponding browser pseudo class. For example, > `data-hover` is equivalent to `:hover`, `data-focus` is equivalent to `:focus`, and `data-active` is equivalent to > `:active`. ### Orientation You can style an element based on its `data-orientation` attribute using the `_horizontal` and `_vertical` modifiers: ```jsx
Hello
``` ## ARIA Attribute You can style an element based on its `aria-{state}=true` attribute using the corresponding `_{state}` modifier: ```jsx
Hello
``` > Most of the `aria-{state}` attributes typically mirror the support ARIA states in the browser pseudo class. For > example, `aria-checked=true` is styled with `_checked`, `aria-disabled=true` is styled with `_disabled`. ## Container queries You can define container names and sizes in your theme configuration and use them in your styles. ```ts export default defineConfig({ // ... theme: { extend: { containerNames: ['sidebar', 'content'], containers: { xs: '40em', sm: '60em', md: '80em' } } } }) ``` The default container sizes in the `@pandacss/preset-panda` preset are shown below: ```ts export const containers = { xs: '320px', sm: '384px', md: '448px', lg: '512px', xl: '576px', '2xl': '672px', '3xl': '768px', '4xl': '896px', '5xl': '1024px', '6xl': '1152px', '7xl': '1280px', '8xl': '1440px' } ``` Then use them in your styles by referencing using `@/` syntax: > The default container syntax is `@/`. ```ts import { css } from '/styled-system/css' function Demo() { return ( ) } ``` This will generate the following CSS: ```css .cq-type_inline-size { container-type: inline-size; } @container (min-width: 60em) { .\@\/sm:fs_md { container-type: inline-size; } } ``` You can also named container queries: ```ts import { cq } from 'styled-system/patterns' function Demo() { return ( ) } ``` ## Reference Here's a list of all the condition shortcuts you can use in Panda: | Condition name | Selector | | ---------------------- | -------------------------------------------------------------------------------------------------| | \_hover | `&:is(:hover, [data-hover])` | | \_focus | `&:is(:focus, [data-focus])` | | \_focusWithin | `&:focus-within` | | \_focusVisible | `&:is(:focus-visible, [data-focus-visible])` | | \_disabled | `&:is(:disabled, [disabled], [data-disabled], [aria-disabled=true])` | | \_active | `&:is(:active, [data-active])` | | \_visited | `&:visited` | | \_target | `&:target` | | \_readOnly | `&:is(:read-only, [data-read-only], [aria-readonly=true])` | | \_readWrite | `&:read-write` | | \_empty | `&:is(:empty, [data-empty])` | | \_checked | `&:is(:checked, [data-checked], [aria-checked=true], [data-state="checked"])` | | \_enabled | `&:enabled` | | \_expanded | `&:is([aria-expanded=true], [data-expanded], [data-state="expanded"])` | | \_highlighted | `&[data-highlighted]` | | \_complete | `&[data-complete]` | | \_incomplete | `&[data-incomplete]` | | \_dragging | `&[data-dragging]` | | \_before | `&::before` | | \_after | `&::after` | | \_firstLetter | `&::first-letter` | | \_firstLine | `&::first-line` | | \_marker | `&::marker, &::-webkit-details-marker` | | \_selection | `&::selection` | | \_file | `&::file-selector-button` | | \_backdrop | `&::backdrop` | | \_first | `&:first-child` | | \_last | `&:last-child` | | \_only | `&:only-child` | | \_even | `&:nth-child(even)` | | \_odd | `&:nth-child(odd)` | | \_firstOfType | `&:first-of-type` | | \_lastOfType | `&:last-of-type` | | \_onlyOfType | `&:only-of-type` | | \_peerFocus | `.peer:is(:focus, [data-focus]) ~ &` | | \_peerHover | `.peer:is(:hover, [data-hover]) ~ &` | | \_peerActive | `.peer:is(:active, [data-active]) ~ &` | | \_peerFocusWithin | `.peer:focus-within ~ &` | | \_peerFocusVisible | `.peer:is(:focus-visible, [data-focus-visible]) ~ &` | | \_peerDisabled | `.peer:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) ~ &` | | \_peerChecked | `.peer:is(:checked, [data-checked], [aria-checked=true], [data-state="checked"]) ~ &` | | \_peerInvalid | `.peer:is(:invalid, [data-invalid], [aria-invalid=true]) ~ &` | | \_peerExpanded | `.peer:is([aria-expanded=true], [data-expanded], [data-state="expanded"]) ~ &` | | \_peerPlaceholderShown | `.peer:placeholder-shown ~ &` | | \_groupFocus | `.group:is(:focus, [data-focus]) &` | | \_groupHover | `.group:is(:hover, [data-hover]) &` | | \_groupActive | `.group:is(:active, [data-active]) &` | | \_groupFocusWithin | `.group:focus-within &` | | \_groupFocusVisible | `.group:is(:focus-visible, [data-focus-visible]) &` | | \_groupDisabled | `.group:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) &` | | \_groupChecked | `.group:is(:checked, [data-checked], [aria-checked=true], [data-state="checked"]) &` | | \_groupExpanded | `.group:is([aria-expanded=true], [data-expanded], [data-state="expanded"]) &` | | \_groupInvalid | `.group:is(:invalid, [data-invalid], [aria-invalid=true]) &` | | \_indeterminate | `&:is(:indeterminate, [data-indeterminate], [aria-checked=mixed], [data-state="indeterminate"])` | | \_required | `&:is(:required, [data-required], [aria-required=true])` | | \_valid | `&:is(:valid, [data-valid])` | | \_invalid | `&:is(:invalid, [data-invalid], [aria-invalid=true])` | | \_userValid | `&:is(:user-valid, [data-user-valid])` | | \_userInvalid | `&:is(:user-invalid, [data-user-invalid])` | | \_autofill | `&:autofill` | | \_inRange | `&:is(:in-range, [data-in-range])` | | \_outOfRange | `&:is(:out-of-range, [data-outside-range])` | | \_placeholder | `&::placeholder, &[data-placeholder]` | | \_placeholderShown | `&:is(:placeholder-shown, [data-placeholder-shown])` | | \_pressed | `&:is([aria-pressed=true], [data-pressed])` | | \_selected | `&:is([aria-selected=true], [data-selected])` | | \_grabbed | `&:is([aria-grabbed=true], [data-grabbed])` | | \_underValue | `&[data-state=under-value]` | | \_overValue | `&[data-state=over-value]` | | \_atValue | `&[data-state=at-value]` | | \_default | `&:default` | | \_optional | `&:optional` | | \_open | `&:is([open], [data-open], [data-state="open"], :popover-open)` | | \_closed | `&:is([closed], [data-closed], [data-state="closed"])` | | \_fullscreen | `&:is(:fullscreen, [data-fullscreen])` | | \_loading | `&:is([data-loading], [aria-busy=true])` | | \_hidden | `&:is([hidden], [data-hidden])` | | \_inert | `&:is([inert], [data-inert])` | | \_current | `&:is([aria-current=true], [data-current])` | | \_currentPage | `&[aria-current=page]` | | \_currentStep | `&[aria-current=step]` | | \_today | `&[data-today]` | | \_unavailable | `&[data-unavailable]` | | \_rangeStart | `&[data-range-start]` | | \_rangeEnd | `&[data-range-end]` | | \_now | `&[data-now]` | | \_topmost | `&[data-topmost]` | | \_motionReduce | `@media (prefers-reduced-motion: reduce)` | | \_motionSafe | `@media (prefers-reduced-motion: no-preference)` | | \_print | `@media print` | | \_landscape | `@media (orientation: landscape)` | | \_portrait | `@media (orientation: portrait)` | | \_dark | `.dark &` | | \_light | `.light &` | | \_osDark | `@media (prefers-color-scheme: dark)` | | \_osLight | `@media (prefers-color-scheme: light)` | | \_highContrast | `@media (forced-colors: active)` | | \_lessContrast | `@media (prefers-contrast: less)` | | \_moreContrast | `@media (prefers-contrast: more)` | | \_ltr | `:where([dir=ltr], :dir(ltr)) &` | | \_rtl | `:where([dir=rtl], :dir(rtl)) &` | | \_scrollbar | `&::-webkit-scrollbar` | | \_scrollbarThumb | `&::-webkit-scrollbar-thumb` | | \_scrollbarTrack | `&::-webkit-scrollbar-track` | | \_horizontal | `&[data-orientation=horizontal]` | | \_vertical | `&[data-orientation=vertical]` | | \_icon | `& :where(svg)` | | \_starting | `@starting-style` | | \_noscript | `@media (scripting: none)` | | \_invertedColors | `@media (inverted-colors: inverted)` | | \_pointerFine | `@media (pointer: fine)` | | \_pointerCoarse | `@media (pointer: coarse)` | | \_pointerNone | `@media (pointer: none)` | | \_anyPointerFine | `@media (any-pointer: fine)` | | \_anyPointerCoarse | `@media (any-pointer: coarse)` | | \_anyPointerNone | `@media (any-pointer: none)` | ## Custom conditions Panda lets you create your own conditions, so you're not limited to the ones in the default preset. Learn more about customizing conditions [here](/docs/design-systems/conditions). --- ## Dynamic styling How to manage dynamic styling in Panda While Panda is mainly focused on the statically analyzable styles, you might need to handle dynamic styles in your project. > We recommend that you **avoid relying on runtime values for your styles** . Consider using recipes, css variables or > `data-*` attributes instead. Here are some ways you can handle dynamic styles in Panda: ## Runtime values Using a value that is not statically analyzable at build-time will not work in Panda due to the inability to determine the style values. ```tsx filename="App.tsx" import { useState } from 'react' import { css } from '../styled-system/css' const App = () => { const [color, setColor] = useState('red.300') return (
) } ``` The example above will not work because Panda can't determine the value of `color` at build-time. Here are some ways to fix this: ### Using Static CSS Panda supports a [`staticCss`](/docs/design-systems/static) option in the config you can use to pre-generate some styles ahead of time. ```tsx filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ staticCss: { css: [ { properties: { // βœ… Good: Pre-generate the styles for the color color: ['red.300'] } } ] } }) ``` ```tsx filename="Button.tsx" import { useState } from 'react' import { styled } from '../styled-system/jsx' export const Button = () => { const [color, setColor] = useState('red.300') // βœ… Good: This will work because `red.300` is pre-generated using `staticCss` config return } ``` ### Using `token()` The `token()` function is generated by Panda and contains an object of all tokens by dot-path, allowing you to query for token's raw value at runtime. ```tsx filename="App.tsx" import { useState } from 'react' import { css } from '../styled-system/css' import { token } from '../styled-system/tokens' const Component = props => { return (
Dynamic color with runtime value
) } // App.tsx const App = () => { const [runtimeColor, setRuntimeColor] = useState('pink.300') return } ``` ### Using `token.var()` You could also directly use the `token.var()` function to get a reference to the underlying CSS custom property for a given token: ```tsx filename="App.tsx" import { useState } from 'react' import { token } from '../styled-system/tokens' const Component = props => { return (
Dynamic color with runtime value
) } const App = () => { const [runtimeColor, setRuntimeColor] = useState('yellow.300') return } ``` ## JSX Style Props Panda supports forwarding JSX style properties to any element in your codebase. For example, let's say we create a Card component that accepts a `color` prop: ```tsx filename="Card.tsx" import { styled } from '../styled-system/jsx' const Card = props => { return } ``` Then you add more style props to the Card component in a different file: ```tsx filename="App.tsx" const App = () => { return (

Some content

) } ``` As long as all prop-value pairs are statically extractable, Panda will automatically generate the CSS, so avoid using runtime values: ```tsx filename="App.tsx" import { useState } from 'react' const App = () => { const [color, setColor] = useState('blue.300') // ❌ Avoid: Panda can't determine the value of color at build-time return (

Some content

) } ``` ## Property Renaming Due to the static nature of Panda, you can't rename properties at runtime. ```tsx filename="App.tsx" import { Circle, CircleProps } from '../styled-system/jsx' type Props = { circleSize?: CircleProps['size'] } const CustomCircle = (props: Props) => { const { circleSize = '3' } = props return ( ) } ``` In this case, use `size` at the call site. ### Alternative As of v0.8, we added a new `{fn}.raw()` method to css, patterns and recipes. This function is an identity function and only serves as a hint for the compiler to extract the css. It can be useful, for example, in Storybook args or custom react props. ```tsx filename="App.tsx" // mark the object as valid css for the extractor ``` `button({ variant: 'accent' })` is a type error if `accent` was never defined, the hand-rolled version above has no equivalent safety net. See [Recipes](/docs/styling/recipes) and [Slot Recipes](/docs/styling/slot-recipes). ## Color Modes Emotion has no built-in color-mode concept, teams typically swap the whole theme object passed to `ThemeProvider` based on some app state, and every user of the theme reads the current mode's value through `useTheme`. Panda's semantic tokens define the light/dark pair once, no theme-swapping or context read at the usage site: ```ts filename="panda.config.ts" theme: { extend: { semanticTokens: { colors: { bg: { value: { base: 'white', _dark: 'gray.900' } } } } } } ``` ```jsx
``` See [Theme](/docs/theming/theme) and [Multiple Themes](/docs/theming/multiple-themes). ## Global Styles Emotion's `Global` component injects styles into the global scope from within your component tree: ```jsx import { Global, css } from '@emotion/react' ``` Panda's equivalent is the `globalCss` key in `panda.config.ts`, declared once in config rather than rendered as a component: ```ts filename="panda.config.ts" export default defineConfig({ globalCss: { body: { margin: 0 } } }) ``` See [Global Styles](/docs/styling/global-styles). ## Component Styles Emotion has no built-in layout primitives, `styled.div`/`styled.section` give you a styled element, but nothing like a pre-built `Box` or `Stack`. Panda ships [patterns](/docs/styling/patterns) for common layout shapes as both a function and a JSX component: ```jsx import { Box, Stack } from '../styled-system/jsx' Item ``` Emotion's `keyframes` helper for animations does carry over directly in spirit, Panda defines keyframes in [`theme.keyframes`](/docs/theming/theme#keyframes) instead of an inline `keyframes()` call, and composes them into named, reusable presets with [Animation Styles](/docs/theming/animation-styles). ## Conclusion Because Emotion is a lower-level library, this migration is less about translating equivalent built-in features (most of what Panda has built in, Emotion doesn't have at all) and more about replacing hand-rolled patterns, a variant function, a manually-swapped theme object, with Panda's typed, declarative equivalents. ## See also - [Migration strategy](/docs/styling/migration-strategy) for running both libraries side by side during the migration. - [Theme UI](/docs/styling/theme-ui) if your app also uses Theme UI's layer on top of Emotion, that guide covers the `sx` prop, variants, and color modes Theme UI adds. --- ## The extend keyword What is and how to to use the extend keyword The `extend` keyword allows you to extend the default Panda configuration. It is useful when you want to add your own customizations to Panda, without erasing the default `presets` values (`conditions`, `tokens`, `utilities`, etc). It will (deeply) merge your customizations with the default ones, instead of replacing them. The `extend` keyword allows you to extend the following parts of Panda: - [conditions](/docs/design-systems/conditions) - [theme](/docs/theming/theme) - [recipes](/docs/styling/recipes) (included in theme) - [patterns](/docs/design-systems/patterns) - [utilities](/docs/design-systems/utilities) - [globalCss](/docs/styling/writing-styles#global-styles) - [staticCss](/docs/design-systems/static) > These keys are all allowed in [presets](/docs/design-systems/presets). ## Example After running the `panda init` command you should see something similar to this: ```ts import { defineConfig } from '@pandacss/dev' export default defineConfig({ // ... // Useful for theme customization theme: { extend: {} // πŸ‘ˆ it's already there! perfect, now you just need to add your customizations in this object } // ... }) ``` Let's say you want to add a new color to the default theme. You can do it like this: ```ts import { defineConfig } from '@pandacss/dev' export default defineConfig({ theme: { extend: { colors: { primary: { value: '#ff0000' } } } } }) ``` This will add a new color to the default theme, without erasing the other ones. Now, let's say we want to create new property `br` that applies a border radius to an element. ```ts import { defineConfig } from '@pandacss/dev' export default defineConfig({ utilities: { extend: { br: { className: 'rounded', // css({ br: "sm" }) => rounded-sm values: 'radii', // connect values to the radii tokens transform(value) { return { borderRadius: value } } } } } }) ``` What if this utility was coming from a preset (`@acme/my-preset`) ? You can extend any specific part, as it will be deeply merged with the existing one: ```ts import { defineConfig } from '@pandacss/dev' export default defineConfig({ presets: ['@acme/my-preset'] utilities: { extend: { br: { className: 'br' // css({ br: "sm" }) => br-sm } } } }) ``` ## Removing something from a preset Let's say you want to remove the `br` utility from the `@acme/my-preset` preset. You can do it like this: ```ts import { defineConfig } from '@pandacss/dev' import myPreset from '@acme/my-preset' const { br, ...utilities } = myPreset.utilities export default defineConfig({ presets: ['@acme/my-preset'] utilities: { extend: { ...utilities, // πŸ‘ˆ we still want the other utilities from this preset // your customizations here } } }) ``` ## Removing something from the base presets Let's say you want to remove the `stack` pattern from the `@pandacss/preset-base` preset (included by default). You can pick only the parts that you need with and spread the rest, like this: ```ts import pandaBasePreset from '@pandacss/preset-base' // omitting stack here const { stack, ...pandaBasePresetPatterns } = pandaBasePreset.patterns export default defineConfig({ // πŸ‘‡ omit `@pandacss/preset-base` from `presets` so it isn't resolved β€” Panda doesn't add it for you presets: ['@pandacss/preset-panda'], // πŸ‘ˆ we still want the tokens, breakpoints and textStyles from this preset patterns: { extend: { ...pandaBasePresetPatterns // your customizations here } } }) ``` ## Minimal setup If you want to use Panda with the bare minimum, without any of the defaults, you can read more about it [here](/docs/design-systems/minimal-setup) ## FAQ ### Why is my preset overriding the base one, even after adding it to the array? You might have forgotten to include the `extend` keyword in your config. Without `extend`, your preset will completely replace the base one, instead of merging with it. --- ## Frequently Asked Questions Frequently asked questions and how to resolve common issues ## How does Panda manage style conflicts ? When you combine shorthand and longhand properties, Panda will resolve the styles in a predictable way. The shorthand property will take precedence over the longhand property. ```jsx import { css } from '../styled-system/css' const styles = css({ paddingTop: '20px', padding: '10px' }) ``` The styles generated at build time will look like this: ```css @layer utilities { .p_10px { padding: 10px; } .pt_20px { padding-top: 20px; } } ``` --- ## Imported Image is not working in Vite App This is a known limitation of Panda due to our static extraction approach. > Think of it this way: there's no way for the compiler to know what the final asset URL will be since Vite controls it. We recommend moving the imported `backgroundImage` to the `style` attribute. ```jsx import myImageBackground from './my-image.png' const Demo = () => { return (

Hello World

) } ``` --- ## How to get Panda to work with Jest? If you run into error messages like `SyntaxError: Unexpected token 'export'` when running Jest tests. Here's what you can: In your tsconfig, add ```json { "compilerOptions": { "allowJs": true } } ``` In your Jest configuration, add the `ts-jest` transformer: ```ts export default { // ... transform: { '^.+\\.tsx?$': 'ts-jest', '^.+\\.(ts|tsx|js|jsx)?$': 'ts-jest' } } ``` In your Panda config, set the `outExtension` to `js`: ```ts export default defineConfig({ // ... outExtension: 'js' }) ``` --- ## HMR does not work when I use `tsconfig` paths? Panda tries to automatically infer and read the custom paths defined in `tsconfig.json` file. However, there might be scenarios where the hot module replacement doesn't work. To fix this add the `importMap` option to your `panda.config.js` file, setting it's value to the specified `paths` in your `tsconfig.json` file. ```json // tsconfig.json { "compilerOptions": { "baseUrl": "./src", "paths": { "@my-path/*": ["./styled-system/*"] } } } ``` ```js // panda.config.js module.exports = { importMap: '@my-path' } ``` This will ensure that the paths are resolved correctly, and HMR works as expected. --- ## HMR not triggered If you are having issues with HMR not being triggered after a `panda.config.ts` change (or one of its [dependencies](/docs/reference/config#dependencies)), you can manually specify the files that should trigger a rebuild by adding the following to your `panda.config.ts`: ```js filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ // ... dependencies: ['path/to/files/**.ts'] }) ``` --- ## Why are my styles not applied? Check that the [`@layer` rules](/docs/styling/cascade-layers#layer-css) are set and the corresponding `.css` file is included. [If you're not using `postcss`](/docs/styling/cli), ensure that `styled-system/styles.css` is imported and that the `panda` command has been run (or is running with `--watch`). --- ## How can I debug the styles? You can use the `panda debug` to debug design token extraction & css generated from files. If the issue persists, you can try looking for it in the [issues](https://github.com/chakra-ui/panda/issues) or in the [discord](https://discord.gg/VQrkpsgSx7). If you can't find it, please create a minimal reproduction and submit [a new github issue](https://github.com/chakra-ui/panda/issues/new/choose) so we can help you. --- ## Why is my IDE not showing `styled-system` imports? If you're not getting import autocomplete in your IDE, you may need to include the `styled-system` directory in your tsconfig.json file. --- ## How do I get a type with each recipe properties? You can get a [`config recipe`](/docs/styling/recipes#config-recipe) properties types by using `XXXVariantProps`. Let's say you have a `config recipe` named `button`, you can import its type like this: ```ts import { button, type ButtonVariantProps } from '../styled-system/recipes' ``` --- You can get an [`atomic recipe`](/docs/styling/recipes#atomic-recipe-or-cva) properties types by using `RecipeVariantProps`. Let's say you have a `atomic recipe` named `button`, you can get its type like this: ```ts import { cva, type RecipeVariantProps } from '../styled-system/css' export type ButtonVariantProps = RecipeVariantProps ``` --- ## How do I split recipe props from the rest? You can split recipe props by using `xxx.splitVariantProps`. Let's say you have a `recipe` named `button`, you can split its props like this: ```tsx Button.tsx {8} import { css, cx } from '../styled-system/css' import { ButtonVariantProps, button } from '../styled-system/recipes' interface ButtonProps extends ButtonVariantProps { children: React.ReactNode } export function Button(props: ButtonProps) { const { children, ...rest } = props const [buttonProps, cssProps] = button.splitVariantProps(rest) return } ``` The same `xxx.splitVariantProps` method is available for both `config recipes` and `atomic recipes`. --- ## How do I reference a token value or css var? You can reference a token value or it's associated css variable using the [`token` function](/docs/theming/usage#vanilla-js). This function allows you to access and use the values stored in your theme tokens at runtime. ```tsx import { token } from '../styled-system/tokens' function App() { return (
) } ``` --- ## Should I commit the styled-system folder? Just like the `node_modules` folder, you most likely don't want to commit the `styled-system` folder. It contains code that is auto-generated and can be re-generated at any time. --- ## How does Panda work? When running `pnpm panda`, here's what's happening under the hood: - **Load Panda context**: - Find and evaluate app config, merge result with presets. - Create panda context: prepare code generator from config, parse user's file as AST. - **Generating artifacts**: - Write lightweight JS runtime and types to output directory - **Extracting used styles in app code**: - Run parser on each user's file: identify and extract styles, compute CSS, write to styles.css. --- ## I'm seeing a "Could not resolve xxx" error with esbuild/tsup. What should I do? In such a case, check the [`outExtension`](/docs/reference/config#outextension) in your `panda.config` and set it to "js". This will ensure your modules are resolved correctly. --- ## Why does importing `styled` not exist? You should use [`config.jsxFramework`](/docs/styling/style-props#configure-jsx) when you need to import styled components. You can then use the [`jsxFactory`](/references/config#jsxfactory) option to set the name of the factory component. --- ## Why is my preset overriding the base one, even after adding it to the array? You might have forgotten to include the `extend` keyword in your config. Without `extend`, your preset will completely replace the base one, instead of merging with it. --- ## Why is my base condition not working in this example? ```ts css({ color: { _base: 'red.600', _dark: 'white' } }) ``` You used `_base` instead of `base`, there is no underscore `_`. --- ## What's the difference between using `defineConfig()` vs `definePreset()` `defineConfig` is intended to be used in your app config, and will show you all the config keys that are available. `definePreset` will only show you the config keys that will be merged into an app's config, the rest will be ignored. --- ## How can I completely override the default tokens?. If you want to **completely override all** of the default presets theme tokens, you can omit the `extends` keyword from your `theme` config object. If you want to **keep some of the defaults**, you can install the `@pandacss/preset-panda` package, import it, then specifically pick what you need in there (or use the JS spread operator `...` and override the other keys). --- ## How do I make a design system / component library with Panda? There is a detailed guide on how to do this [here](/docs/design-systems/overview). --- ## Can I use dynamic styles with Panda? Yes, you can use dynamic styles with Panda. More on that [here](/docs/styling/dynamic-styling#runtime-conditions). --- ## Should I use atomic or config recipes ? [Config recipes](/docs/styling/recipes#config-recipe) are generated just in time, meaning that only the recipes and variants you use will exist in the generated CSS, regardless of the number of recipes in the config. This contrasts with [Atomic recipes](/docs/styling/recipes#atomic-recipe-or-cva) (cva), which generates all of the variants regardless of what was used in your code. The reason for this difference is that all `config.recipes` are known at the start of the panda process when we evaluate your config. In contrast, the CVA recipes are scattered throughout your code. To get all of them and find their usage across your code, we would need to scan your app code multiple times, which would not be ideal performance-wise. When dealing with simple use cases, or if you need code colocation, or even avoiding dynamic styling, atomic recipes shine by providing all style variants. Config recipes are preferred for design system components, delivering leaner CSS with only the styles used. Choose according to your component needs. --- ## Why does the panda codegen command fail ? If you run into any error related to "Transforming const to the configured target environment ("es5") is not supported yet", update your tsconfig to use es6 or higher: ```json filename="tsconfig.json" { "compilerOptions": { "target": "es6" } } ``` --- ## How can I generate all possible CSS variants at build time? While it's possible to generate all variants, even unused ones, by using [`config.staticCss`](https://panda-css.com/docs/styling/dynamic-styling#using-static-css), it's generally **not recommended** to use it for more than a few values. However, keep in mind this approach compromises one of Panda's strengths: lean, usage-based CSS generation. --- ## Can I use one-off media query and other at rules? Yes, you can! You can apply one-off media queries and other at rules (such as `@container`, `@supports`) in your CSS as shown below: ```javascript css({ containerType: 'size', '@media (min-width: 10px)': { fontSize: 'xl', color: 'blue.300' }, '@container (min-width: 10px)': { fontSize: '2xl', color: 'green.300' }, '@supports (display: flex)': { fontSize: '3xl', color: 'red.300' } }) ``` --- ## How can I prevent other libraries from overriding my styles? You can use [Layer Imports]() to prevent other libraries from overriding your styles. First of all you cast the css from the other library(s) to a css layer: ```css @import url('bootstrap.css') layer(bootstrap); @import url('ionic.css') layer(ionic); ``` Then update the default layer list to deprioritize the styles from the other library(s): ```css @layer bootstrap, reset, base, token, recipes, utilities; @layer ionic, reset, base, token, recipes, utilities; ``` --- ## Using Gatsby Easily use Panda with Gatsby with our dedicated integration. This guide shows you how to set up Panda CSS in a Gatsby project using PostCSS. ### Create Gatsby project To get started, we will need to create a new Gatsby project. We will name our project `test-app` but you can name it whatever you want. If you don't enter any parameter, the CLI will guide you through the process of creating a new Gatsby app. ```bash npm init gatsby ``` You will be asked a few questions, answer them as follows: ``` βœ” What would you like to call your site? ... My Gatsby Site βœ” What would you like to name the folder where your site will be created? ... projects/ test-app βœ” Will you be using JavaScript or TypeScript? ... TypeScript βœ” Will you be using a CMS? ... No (or I'll add it later) βœ” Would you like to install a styling system? ... No (or I'll add it later) βœ” Would you like to install additional features with other plugins? ... No items were selected ``` Enter the newly created directory: ```bash cd test-app ``` ### Install Panda CSS Install Panda CSS and `gatsby-plugin-postcss` to your project. After that run the `panda init` command to setup Panda CSS in your project. ```bash npm install -D @pandacss/dev postcss gatsby-plugin-postcss npx panda init --postcss ``` ### Setup the Gatsby PostCSS plugin Include the plugin in your `gatsby-config.ts` file. Check out the [official documentation](https://www.gatsbyjs.com/plugins/gatsby-plugin-postcss/) for more information. ```ts {9} filename="gatsby-config.ts" import type { GatsbyConfig } from 'gatsby' const config: GatsbyConfig = { siteMetadata: { title: `My Gatsby Site`, siteUrl: `https://www.yourdomain.tld` }, graphqlTypegen: true, plugins: [`gatsby-plugin-postcss`] } export default config ``` ### Update package.json scripts Open your `package.json` file and update the `scripts` section as follows: ```diff {3} filename="package.json" { "scripts": { + "prepare": "panda codegen", "develop": "gatsby develop", "start": "gatsby develop", "build": "gatsby build", "serve": "gatsby serve", "clean": "gatsby clean", "typecheck": "tsc --noEmit" } } ``` - `"prepare"` - script that will run Panda CSS CLI codegen before each build. Read more about [codegen](/docs/reference/cli#codegen) in the CLI section. > This step ensures that the panda output directory is regenerated after each dependency installation. So you can add > the output directory to your `.gitignore` file and not worry about it. ### Configure the content Make sure that all of the paths of your React components are included in the `include` section of the `panda.config.ts` file. > If you use [GraphQL Typegen](/docs/how-to/local-development/graphql-typegen/), you'll need to update the `include` to > avoid infinite loop due to generated `src/gatsby-types.d.ts`. ```js {6} filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ preflight: true, // Where to look for your css declarations include: ['./src/pages/*.{js,jsx,ts,tsx}', './src/components/**/*.{js,jsx,ts,tsx}'], exclude: [], outdir: 'styled-system' }) ``` ### Configure the entry CSS with layers Create `src/styles/index.css` file and add the following content: ```css filename="src/styles/index.css" @layer reset, base, tokens, recipes, utilities; ``` ### Import the entry CSS Create a `gatsby-browser.ts` file in the root of your project and add the following content: ```ts filename="gatsby-browser.ts" import './src/styles/index.css' ``` ### Start your build process Run the following command to start your development server. ```bash npm run develop ``` ### Start using Panda Now you can start using Panda CSS in your project. Here is the snippet of code that you can use in your `src/pages/index.tsx` file. ```tsx {3,7} filename="src/pages/index.tsx" import * as React from 'react' import type { HeadFC, PageProps } from 'gatsby' import { css } from '../../styled-system/css' const IndexPage: React.FC = () => { return
Hello 🐼!
} export default IndexPage export const Head: HeadFC = () => Home Page ```
## Troubleshooting If you're not getting import autocomplete in your IDE, you may need to include the `styled-system` directory in your `tsconfig.json` file: ```json filename="tsconfig.json" { // ... "include": ["src", "styled-system"] } ``` --- ## Welcome to Panda The universal design system solution for the web Panda is a styling engine that generates styling primitives to author atomic CSS and recipes in a type-safe and readable manner. Panda combines the developer experience of CSS-in-JS and the performance of atomic CSS. It leverages static analysis to scan your JavaScript and TypeScript files for JSX style props and function calls, generating styles on-demand (aka Just-in-Time) > TLDR; Panda is a CSS-in-JS engine that generates atomic CSS at build time (via CLI or PostCSS) ## Why Panda - **Static analysis:** Panda parses your styles at build time and generates plain CSS files that work in any JavaScript framework. - **Type safety:** Panda combines `csstype` with auto-generated typings, so CSS properties and design tokens are type-checked as you write them. - **Performance:** styles compile down to atomic CSS ahead of time, so there's no runtime style engine shipped to the browser. - **Developer experience:** recipes, patterns, design tokens, and JSX style props give you a consistent way to author styles without hand-rolling your own system. - **Modern CSS:** generated styles use cascade layers, CSS variables, and modern selectors like `:where` and `:is`. Here's what using Panda looks like in practice: ```jsx import { css } from '../styled-system/css' import { circle, stack } from '../styled-system/patterns' function App() { return (
avatar
John Doe
john@doe.com
) } ``` ## Installation Panda can be installed as a CLI tool, a PostCSS plugin, through a framework-specific guide, or inside Storybook. ## Next Steps Get familiar with the core features and concepts in Panda. ## Playground You can use the [online playground](https://play.panda-css.com) to get a taste of what Panda can do. - See the live results of your JSX code - Inspect what panda can extract using static analysis from your code - Preview the statically generated `.css` files ## Acknowledgement The development of Panda was only possible due to the inspiration and ideas from these amazing projects. - [Chakra UI](https://chakra-ui.com/) - where it all started - [Vanilla Extract](https://vanilla-extract.style/) - for inspiring the utilities API - [Stitches](https://stitches.dev/) - for inspiring the recipes and variants API - [Tailwind CSS](https://tailwindcss.com/) - for inspiring the JIT compiler and strategy - [Class Variance Authority](https://cva.style/) - for inspiring the `cva` name - [Styled System](https://styled-system.com/) - for the initial idea of Styled Props - [Linaria](https://linaria.dev/) - for inspiring the initial atomic css strategy - [Uno CSS](https://unocss.dev) - for inspiring the studio and astro integration --- ## Global Styles How to work with resets, global styles, and global CSS variables in Panda. Panda groups global styles into reset and base layers so you can control defaults predictably and override them safely. ## Layers overview - **@layer reset**: Preflight/reset styles, enabled with `preflight`. - **@layer base**: Your additional global styles via `globalCss`. > See also: [Cascade layers](/docs/styling/cascade-layers) ## Reset (preflight) Enable or scope the reset styles. ```ts filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ preflight: true }) ``` Scope and level: ```ts filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ preflight: { scope: '.extension', level: 'element' } }) ``` ## Exposed global CSS variables These variables are used by the reset and defaults. Set them in `globalCss`: - `--global-font-body` - `--global-font-mono` - `--global-color-border` - `--global-color-placeholder` - `--global-color-selection` - `--global-color-focus-ring` ## Setting global styles (base) Use `globalCss` to define additional global styles and set variables. ```ts filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ // ... globalCss: { html: { '--global-font-body': 'Inter, sans-serif', '--global-font-mono': 'Mononoki Nerd Font, monospace', '--global-color-border': 'colors.gray.400', '--global-color-placeholder': 'rgba(0,0,0,0.5)', '--global-color-selection': 'rgba(0,115,255,0.3)', '--global-color-focus-ring': 'colors.blue.400' } } }) ``` ### Theming patterns You can set variables on `:root`, a `.dark` class, or via media queries. ```css :root { --global-color-border: oklch(0.8 0 0); } .dark { --global-color-border: oklch(0.72 0 0); } @media (prefers-color-scheme: dark) { :root { --global-color-border: oklch(0.72 0 0); } } ``` ## Custom global variables (`globalVars`) Define additional global CSS variables or `@property` entries. ```ts filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ globalVars: { '--button-color': { syntax: '', inherits: false, initialValue: 'blue' } } }) ``` > Keys from `globalVars` are suggestable in style objects and generated near your tokens at `cssVarRoot`. ### Variables owned by a utility A utility that writes a CSS variable declares the registration itself, so the two can't drift apart: ```ts filename="panda.config.ts" export default defineConfig({ utilities: { blur: { className: 'blur', globalVars: { '--blur': { syntax: '*', inherits: false } }, transform: (value) => ({ '--blur': `blur(${value})` }) } } }) ``` Only the utility that *writes* the variable needs to declare it. A second utility that reads it β€” `filter: 'auto'` composing `var(--blur, )` β€” declares nothing. These merge into `globalVars`, and Panda drops any registration your stylesheet never references. Declaring one costs nothing until it's used, which is how `preset-base` registers dozens of them without charging projects that don't mask, transform, or filter. Two rules keep collisions honest: - Two utilities registering the same name with different definitions is a config error. A CSS variable has one registration for the whole document, so share one definition between them. - Putting a plain value on a name a utility registered warns, because the value drops the `@property` registration and starts the variable inheriting. Pass a full `@property` object if you meant to retune it. The warning only appears when your stylesheet actually reads that variable, so reusing a name the preset happens to reserve is fine as long as the two never meet. ### Older browsers `@property` needs Chrome 85+, Safari 16.4+, or Firefox 128+. Engines without it skip the registration entirely, so a declaration that reads an unregistered variable is dropped β€” the utility silently does nothing. Set `optimize.propertyFallback` to also seed the defaults as plain declarations: ```ts filename="panda.config.ts" export default defineConfig({ optimize: { propertyFallback: true } }) ``` Panda derives the seeds from the registrations it actually emitted, so you only pay for the variables your project uses. Modern engines ignore them. ## Troubleshooting - **Global styles aren't applied:** Confirm `preflight` is enabled (if you expect reset), and ensure your selector (`html`, `:root`, `.dark`, etc.) matches the element where variables are set. - **Global styles are overridden by utilities or component styles:** Verify layer order and specificity. Ensure `@layer reset` and `@layer base` are emitted before utilities. If you customize insertion or injection order (SSR, framework plugins), preserve `@layer` order so globals are not overridden. --- ## How Panda works The mental model behind Panda's static extraction, why css() calls don't cost anything at runtime. Panda looks like a normal CSS-in-JS library at the call site, `css({ bg: 'red.500' })` returns a class name. What makes it different is that nothing runs in the browser to produce that class name. This page is the mental model for why, useful before you hit [Dynamic Styles](/docs/styling/dynamic-styling) and wonder why some patterns don't work. ## Two separate steps, not one It's easy to assume "generating my styled-system" and "generating my CSS" are the same step. They're not, and Panda actually runs them in this order every time you build: 1. **Codegen.** Panda reads `panda.config.ts`, resolves your tokens, utilities, conditions, and recipes, and writes the `styled-system` package, the actual `css()`, `cva()`, pattern, and token files you import from. This step doesn't look at your application code at all, it only depends on your config. 2. **Extraction.** Panda then scans your source files (everything matched by [`include`](/docs/reference/config#include)) for calls to the functions codegen just produced, `css()`, `cva()`, JSX style props, and so on. Only the styles your code actually calls get turned into CSS rules. Everything else in the generated `styled-system` package stays unused code that never reaches a stylesheet. The output of step 2, one CSS file, is the only thing that ships to the browser. There's no client-side style engine reading your `css()` calls at runtime, by the time your app runs, the class names are already plain strings and the CSS already exists. ## What makes a value extractable Because step 2 works by reading your source code as text (not by running it), Panda needs your style calls to be statically analyzable, values it can determine by looking at the code, not by executing it. `css({ bg: 'red.500' })` is extractable, `css({ bg: someVariableComputedAtRuntime })` generally isn't, because Panda can't know what that variable will be without running your program. This is the root cause behind most "why isn't my style showing up" questions, see [Dynamic Styles](/docs/styling/dynamic-styling) for the specific patterns that work around it. ## The tradeoff The payoff is that Panda adds zero runtime, no style computation, no context reads, no re-render cost from styling itself, since everything is already resolved into a static CSS file before the browser ever sees your app. The tradeoff is the one above: styles have to be discoverable by static analysis, which is a real constraint compared to a runtime library that can compute anything a JavaScript expression can compute. ## See also - [Writing Styles](/docs/styling/writing-styles) for the `css()` API this pipeline is built around. - [Dynamic Styles](/docs/styling/dynamic-styling) for the specific escape hatches when a value truly can't be known at build time. - [Cascade Layers](/docs/styling/cascade-layers) for how the generated CSS file is organized once extraction produces it. - [Debugging](/docs/reference/debugging) to inspect what extraction actually saw for a given file. --- ## Installation Install Panda CSS via the CLI, PostCSS, your framework, or Storybook. Panda can be installed a few different ways: as a standalone CLI tool, as a PostCSS plugin, through one of our framework-specific guides, or inside Storybook. Pick the tab below that matches your setup. This guide shows you how to use Panda as an alternative approach by running the Panda CLI tool. ### Install Panda ```bash pnpm install -D @pandacss/dev pnpm panda init ``` ```bash npm install -D @pandacss/dev npx panda init ``` ```bash yarn add -D @pandacss/dev yarn panda init ``` ```bash bun add -D @pandacss/dev bun panda init ``` ### Configure the content Add the paths to all of your JavaScript or TypeScript code where you intend to use panda. ```js {5} import { defineConfig } from '@pandacss/dev' export default defineConfig({ preflight: true, include: ['./src/**/*.{ts,tsx,js,jsx}', './pages/**/*.{ts,tsx,js,jsx}'], exclude: [], outdir: 'styled-system' }) ``` ### Update package.json scripts Open your `package.json` file and update the `scripts` section as follows: ```diff {3} { "scripts": { + "prepare": "panda codegen", } } ``` The `prepare` script that will run codegen after dependency installation. Read more about [codegen](/docs/reference/cli#codegen) in the CLI section. > This step ensures that the panda output directory is regenerated after each dependency installation. So you can add > the output directory to your `.gitignore` file and not worry about it. ### Import the generated CSS For each Panda run, it emits the generated CSS at the `styled-system/styles.css` file path. Import this file at the root component of your project. ```jsx {1} import './styled-system/styles.css' export function App() { return
Page
} ``` ### Start the Panda build process Run the CLI tool to scan your JavaScript and TypeScript files for style properties and call expressions. ```bash # Run it once pnpm panda # Run it in watch mode pnpm panda --watch ``` ```bash # Run it once npx panda # Run it in watch mode npx panda --watch ``` ```bash # Run it once yarn panda # Run it in watch mode yarn panda --watch ``` ```bash # Run it once bun panda # Run it in watch mode bun panda --watch ``` ### Start using Panda Use the generated style utilities in your code and panda will extract them to the generated CSS file. Then run your build process. ```jsx import { css } from './styled-system/css' export function App() { return
} ``` #### Troubleshooting If you're not getting import autocomplete in your IDE, you may need to include the `styled-system` directory in your `tsconfig.json` file: ```json filename="tsconfig.json" { // ... "include": ["src", "styled-system"] } ``` This guide shows you how to install Panda as a PostCSS plugin, which is the recommended way to integrate it with your project. ### Install Panda Install panda and create your `panda.config.ts` file. ```bash pnpm install -D @pandacss/dev postcss pnpm panda init -p ``` ```bash npm install -D @pandacss/dev postcss npx panda init -p ``` ```bash yarn add -D @pandacss/dev postcss yarn panda init -p ``` ```bash bun add -D @pandacss/dev postcss bun panda init -p ``` ### Add Panda to your PostCSS config Add panda to your `postcss.config.cjs` file, or wherever PostCSS is configured in your project. ```js module.exports = { plugins: { '@pandacss/dev/postcss': {} } } ``` ### Configure the content Add your panda config to your `panda.config.js` file, or wherever panda is configured in your project. ```js {5} import { defineConfig } from '@pandacss/dev' export default defineConfig({ preflight: true, include: ['./src/**/*.{ts,tsx,js,jsx}', './pages/**/*.{ts,tsx,js,jsx}'], exclude: [], outdir: 'styled-system' }) ``` ### Update package.json scripts Open your `package.json` file and update the `scripts` section as follows: ```diff {3} { "scripts": { + "prepare": "panda codegen", } } ``` The `prepare` script will run codegen after dependency installation. Read more about [codegen](/docs/reference/cli#codegen) in the CLI section. > This step ensures that the panda output directory is regenerated after each dependency installation. So you can add > the output directory to your `.gitignore` file and not worry about it. ### Configure the entry CSS with layers Add this code to an `index.css` file which is going to be the root css of your project. ```css @layer reset, base, tokens, recipes, utilities; ``` ### Start your build process Run your build process by feeding the [root css](#configure-the-entry-css-with-layers) to PostCSS in your preferred way. ```bash postcss -o output.css index.css ``` ```js const postcss = require("postcss"); const fs = require("fs"); fs.readFile("index.css", (err, css) => { postcss() .process(css, { from: "index.css", to: "output.css" }) .then((result) => { console.log(result.css); }); }); ``` > If you're using a framework, PostCSS is probably already integrated with your build process. Check our other guides or > the documentation of your framework to see how to configure PostCSS. ### Start using Panda Use the generated style utilities in your code and panda will extract them to the generated CSS file. ```jsx import { css } from './styled-system/css' export function App() { return
} ``` #### Troubleshooting If you're not getting import autocomplete in your IDE, you may need to include the `styled-system` directory in your `tsconfig.json` file: ```json filename="tsconfig.json" { // ... "include": ["src", "styled-system"] } ``` Start using Panda CSS in your JavaScript framework using our framework-specific guides that cover our recommended approach. We are assuming that you already have a project set up with a framework like React, Vue or Svelte. ### Install Storybook Storybook needs to be installed into a project that is already set up with a framework. It will not work on an empty project. ```bash pnpm dlx storybook@latest init ``` ```bash npx storybook@latest init ``` ```bash yarn dlx storybook@latest init ``` ```bash bunx storybook@latest init ``` ### Install Panda Install panda and create your `panda.config.ts` file. ```bash pnpm install -D @pandacss/dev pnpm panda init --postcss ``` ```bash npm install -D @pandacss/dev npx panda init --postcss ``` ```bash yarn add -D @pandacss/dev yarn panda init --postcss ``` ```bash bun add -D @pandacss/dev bun panda init --postcss ``` If you are using Storybook with the Vite builder, you will have to update your PostCSS config file to use the array syntax for the plugins instead of the object syntax. Simply change `postcss.config.cjs`: ```diff filename="postcss.config.cjs" module.exports = { - plugins: { - '@pandacss/dev/postcss': {} - } + plugins: [require('@pandacss/dev/postcss')()] } ``` ### Update package.json scripts Open your `package.json` file and update the `scripts` section as follows: ```diff {3} filename="web/package.json" { "scripts": { + "prepare": "panda codegen" } } ``` - `"prepare"` - script that will run Panda CSS CLI codegen before each build. Read more about [codegen](/docs/reference/cli#codegen) in the CLI section. > This step ensures that the panda output directory is regenerated after each dependency installation. So you can add > the output directory to your `.gitignore` file and not worry about it. ### Configure the content Make sure that all of the paths of your Storybook components are included in the `include` section of the `panda.config.ts` file. ```ts {7} filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ // Whether to use css reset preflight: true, // Where to look for your css declarations include: ['./src/**/*.{js,jsx,ts,tsx}', './pages/**/*.{js,jsx,ts,tsx}', './stories/**/*.{js,jsx,ts,tsx}'], // Files to exclude exclude: [], // The output directory for your css system outdir: 'styled-system' }) ``` ### Configure the entry CSS with layers Locate your main CSS file and add the following layers: ```css filename="src/index.css" @layer reset, base, tokens, recipes, utilities; ``` ### Import the CSS in your Storybook config Locate your `.storybook/preview.ts` file and import the CSS file. In this example CSS file is located in the `src` folder. ```ts {1} filename=".storybook/preview.ts" import '../src/index.css' import type { Preview } from '@storybook/react' const preview: Preview = { parameters: { actions: { argTypesRegex: '^on[A-Z].*' }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/ } } } } export default preview ``` ### Start the Storybook server Run the following command to start your Storybook server. ```bash pnpm storybook ``` ```bash npm run storybook ``` ```bash yarn storybook ``` ```bash bun storybook ``` ### Start using Panda Now you can start using Panda CSS in Storybook. Here is the example of a Button component and its corresponding Storybook story: ```tsx filename="src/stories/Button.tsx" import { ReactNode } from 'react' import { css } from '../../styled-system/css' export interface IButtonProps { children: ReactNode } export const Button = ({ children }: IButtonProps) => { return ( ) } ``` ```tsx filename="src/stories/Button.stories.tsx" import type { Meta, StoryObj } from '@storybook/react' import { css } from '../../styled-system/css' import { Button } from './Button' const meta = { title: 'Example/Button', component: Button, tags: ['autodocs'], decorators: [ Story => (
) ] } satisfies Meta export default meta type Story = StoryObj export const Default: Story = { args: { children: 'Hello 🐼!' } } ```
#### Configuring Dark Mode To enable dark mode in Storybook, you can use the `@storybook/addon-themes` package. ```bash pnpm add -D @storybook/addon-themes ``` Then, update your `.storybook/preview.ts` file to include the following: ```ts filename=".storybook/preview.ts" import { withThemeByClassName } from '@storybook/addon-themes' import type { Preview, ReactRenderer } from '@storybook/react' const preview: Preview = { // ... decorators: [ withThemeByClassName({ themes: { light: '', dark: 'dark' }, defaultTheme: 'light' }) ] } export default preview ``` With that in place, you should see the light/dark switcher in Storybook's toolbar. #### Troubleshooting ##### Cannot find postcss plugin If you are having issues with the PostCSS plugin similar to `Cannot find module '@pandacss/dev/postcss'`, update the PostCSS config as follows: ```js filename="postcss.config.cjs" module.exports = { plugins: [require('@pandacss/dev/postcss')] } ``` ##### HMR not triggered If you are having issues with HMR not being triggered after a `panda.config.ts` change (or one of its [dependencies](/docs/reference/config#dependencies), you can manually specify the files that should trigger a rebuild by adding the following to your `panda.config.ts`: ```js filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ // ... dependencies: ['path/to/files/**.ts'] }) ``` ##### Styles in `args` is not generated If you are having issues with your `args` not generating the expected CSS, it's probably because of: - you didn't add a file glob for the Storybook files in your [`config.include`](/docs/reference/config#include) like `"./stories/**/*.{js,jsx,ts,tsx}"` - you didn't wrap your `args` object (or some part of it) with the [`.raw()` marker that helps Panda find style usage](https://panda-css.com/docs/styling/dynamic-styling#alternative) ```tsx filename="stories/Button.stories.tsx" import type { Meta, StoryObj } from '@storybook/react' import { button } from '../../styled-system/recipes' export const Funky: Story = { // mark this as a button recipe usage args: button.raw({ visual: 'funky', shape: 'circle', size: 'sm' }) } ``` ##### Some recipes styles are missing If you are having issues with your config `recipes` or `slotRecipes` not generating the expected CSS, it's probably because of: - you didn't add a file glob for the Storybook files in your [`config.include`](/docs/reference/config#include) like `"./stories/**/*.{js,jsx,ts,tsx}"` - you haven't used every recipes variants in your app, so you might want to pre-generate it (only for storybook usage) with [`staticCss`](/docs/design-systems/static) ```tsx filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ // ... staticCss: { recipes: '*' } }) ```
--- ## JSX Style Context JSX Style Context provides an ergonomic way to style compound components with slot recipes. It uses a context-based approach to distribute recipe styles across multiple child components, making it easier to style headless UI libraries like Ark UI, and Radix UI. ## Atomic Slot Recipe - Create a slot recipe using the `sva` function - Pass the slot recipe to the `createSlotRecipeContext` function - Use the `withProvider` and `withContext` functions to create compound components ```tsx // components/ui/card.tsx import { sva } from 'styled-system/css' import { createSlotRecipeContext } from 'styled-system/jsx' const card = sva({ slots: ['root', 'label'], base: { root: {}, label: {} }, variants: { size: { sm: { root: {} }, md: { root: {} } } }, defaultVariants: { size: 'sm' } }) const { withProvider, withContext } = createSlotRecipeContext(card) const Root = withProvider('div', 'root') const Label = withContext('label', 'label') export const Card = { Root, Label } ``` Then you can use the `Root` and `Label` components to create a card. ```tsx // app/page.tsx import { Card } from './components/ui/card' export default function App() { return ( Hello ) } ``` ## Config Slot Recipe The `createSlotRecipeContext` function can also be used with slot recipes defined in the `panda.config.ts` file. - Pass the config recipe to the `createSlotRecipeContext` function - Use the `withProvider` and `withContext` functions to create compound components ```tsx // components/ui/card.tsx import { card } from '../styled-system/recipes' import { createSlotRecipeContext } from 'styled-system/jsx' const { withProvider, withContext } = createSlotRecipeContext(card) const Root = withProvider('div', 'root') const Label = withContext('label', 'label') export const Card = { Root, Label } ``` Then you can use the `Root` and `Label` components to create a card. ```tsx // app/page.tsx import { Card } from './components/ui/card' export default function App() { return ( Hello ) } ``` ## createSlotRecipeContext Use this for a slot recipe (`sva` or `defineSlotRecipe`) with multiple parts. It's a factory function that returns three functions: `withRootProvider`, `withProvider`, and `withContext`. ### withRootProvider Creates the root component that provides the style context. Use this when the root component **does not render an underlying DOM element**. ```tsx import { Dialog } from '@ark-ui/react' //... const DialogRoot = withRootProvider(Dialog.Root) ``` ### withProvider Creates a component that both provides context and applies the root slot styles. Use this when the root component **renders an underlying DOM element**. > **Note:** It requires the root `slot` parameter to be passed. ```tsx import { Avatar } from '@ark-ui/react' //... const AvatarRoot = withProvider(Avatar.Root, 'root') ``` ### withContext Creates a component that consumes the style context and applies slot styles. It does not accept variant props directly, but gets them from context. ```tsx import { Avatar } from '@ark-ui/react' //... const AvatarImage = withContext(Avatar.Image, 'image') const AvatarFallback = withContext(Avatar.Fallback, 'fallback') ``` ### unstyled prop Every component created with `createSlotRecipeContext` supports the `unstyled` prop to disable styling. It is useful when you want to opt-out of the recipe styles. - When applied the root component, will disable all styles - When applied to a child component, will disable the styles for that specific slot ```tsx // Removes all styles // Removes only the styles for the image slot ``` ## createRecipeContext Use this for a single-element config recipe (`cva` or `defineRecipe`) that has no slots. It returns a single `withContext` function, and `withContext` takes just the element or component, with no slot name. ```tsx import { button } from '../styled-system/recipes' import { createRecipeContext } from 'styled-system/jsx' const { withContext } = createRecipeContext(button) export const Button = withContext('button') ``` The component accepts the recipe's variant props and forwards them to drive the styling. ## Guides ### Config Recipes The rules of config recipes still applies when using `createSlotRecipeContext`. Ensure the name of the final component matches the name of the recipe. > If you want to use a custom name, you can configure the recipe's `jsx` property in the `panda.config.ts` file. ```tsx // recipe name is "card" import { card } from '../styled-system/recipes' const { withRootProvider, withContext } = createSlotRecipeContext(card) const Root = withRootProvider('div') const Header = withContext('header', 'header') const Body = withContext('body', 'body') // The final component name must be "Card" export const Card = { Root, Header, Body } ``` ### Default Props Use `defaultProps` option to provide default props to the component. ```tsx const { withContext } = createSlotRecipeContext(card) export const CardHeader = withContext('header', 'header', { defaultProps: { role: 'banner' } }) ``` ### Forwarding props `withProvider` uses variant props to style the slots, but doesn't pass them to your component. When you need a variant value inside the component, list it in `forwardProps`. It still styles the slot, and now your component receives it too. ```tsx const tabs = sva({ slots: ['root', 'tab'], base: { root: { display: 'flex' } }, variants: { orientation: { horizontal: { root: { flexDirection: 'row' } }, vertical: { root: { flexDirection: 'column' } } } } }) const { withProvider } = createSlotRecipeContext(tabs) function TabsRoot({ orientation, ...rest }: TabsRootProps) { // `orientation` is available here, so we can mirror it as an aria attribute return
} export const Tabs = withProvider(TabsRoot, 'root', { forwardProps: ['orientation'] }) ``` `forwardProps` works on `withContext` too. Since context consumers don't take variant props, it's mainly useful for forwarding props that share a name with a CSS property, since otherwise they'd be turned into styles instead of reaching your component. ```tsx // `width` would normally become a style. Forward it to the component instead const TabIndicator = withContext(Indicator, 'indicator', { forwardProps: ['width'] }) ``` --- ## LLMs.txt Help AI tools understand Panda CSS with LLMs.txt support. ## What is LLMs.txt? [LLMs.txt](https://llmstxt.org/) files are used to provide the Panda CSS documentation to large language models (LLMs). This helps AI tools better understand our styling engine, its APIs, and usage patterns. ## Available Routes These routes are available to help AI tools access our documentation: - [/llms.txt](/llms.txt) - Contains a structured overview of all concepts and their documentation links - [/llms-full.txt](/llms-full.txt) - Provides comprehensive documentation including implementation details and examples ## Access Individual Pages You can also access the raw markdown content for any documentation page by adding `.mdx` to the end of the URL. For example: - [`/docs/styling/getting-started.mdx`](/docs/styling/getting-started.mdx) - Raw markdown for the welcome page - [`/docs/styling/recipes.mdx`](/docs/styling/recipes.mdx) - Raw markdown for the recipes documentation - [`/docs/theming/tokens.mdx`](/docs/theming/tokens.mdx) - Raw markdown for the tokens documentation This is useful for AI tools that need to access specific documentation sections directly. ## Usage with AI Tools ### Cursor Use the `@Docs` feature in Cursor to include the LLMs.txt files in your project. This helps Cursor provide more accurate code suggestions and documentation for Panda CSS. [Read more about @Docs in Cursor](https://docs.cursor.com/context/@-symbols/@-docs) ### Windsurf Reference the LLMs.txt files using `@` or in your `.windsurfrules` files to enhance Windsurf's understanding of Panda CSS. [Read more about Windsurf Memories](https://docs.codeium.com/windsurf/memories#memories-and-rules) ### Other AI Tools Any AI tool that supports LLMs.txt can use these routes to better understand Panda CSS. Simply point your tool to any of the routes above to get comprehensive documentation about our styling engine. --- ## MCP Server Expose your Panda CSS design system to AI assistants using the Model Context Protocol (MCP). The Panda MCP Server allows AI assistants like Claude, Cursor, VS Code Copilot, Windsurf, and Codex to understand and work with your project's design system. It provides tools for querying tokens, recipes, patterns, conditions, and more. ## What is MCP? The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) is an open standard for connecting AI assistants to external tools and data sources. Panda's MCP server exposes your design system through a set of specialized tools that AI assistants can use to: - Look up design tokens and their values - Understand available component recipes and variants - Query layout patterns and their properties - Analyze token and recipe usage across your codebase ## Quick Start ### 1. Add the MCP Server Add the Panda MCP server to your AI client's MCP configuration: ```json { "mcpServers": { "panda": { "command": "npx", "args": ["-y", "@pandacss/mcp"] } } } ``` For VS Code, use the `servers` key instead of `mcpServers`. ### 2. Use with Your AI Assistant Once configured, your AI assistant will automatically have access to Panda CSS tools. You can ask questions like: - "What color tokens are available in my design system?" - "Show me the button recipe variants" - "Which tokens are unused in my codebase?" - "What breakpoints are defined?" ## CLI Commands The MCP server is distributed as `@pandacss/mcp`. It is usually started by your AI client, but you can also run it directly with `npx`, `pnpm dlx`, or your package manager's equivalent one-off package runner. Start the MCP server manually (usually not needed - clients start it automatically). ```bash pnpm dlx @pandacss/mcp # With custom config path pnpm dlx @pandacss/mcp --config ./panda.config.ts # Specify working directory pnpm dlx @pandacss/mcp --cwd ./my-project ``` | Flag | Description | | --------------------- | ------------------------- | | `--config, -c ` | Path to Panda config file | | `--cwd ` | Current working directory | | `--silent` | Suppress startup logs | ## Supported AI Clients The MCP server can be used with AI assistants that support local stdio MCP servers: | Client | Typical Config Path | Config Key | | -------- | -------------------- | ------------ | | Claude | `.mcp.json` | `mcpServers` | | Cursor | `.cursor/mcp.json` | `mcpServers` | | VS Code | `.vscode/mcp.json` | `servers` | | Windsurf | `.windsurf/mcp.json` | `mcpServers` | | Codex | `.codex/mcp.json` | `mcpServers` | ## Available Tools The MCP server exposes these tools to AI assistants: | Tool | Description | Input | | ---------------------- | ------------------------------------------------------------------- | ----------------------------------------- | | `get_tokens` | Get design tokens with values, CSS variables, and usage examples | `category?` - filter by token category | | `get_semantic_tokens` | Get semantic tokens with conditional values (dark mode, responsive) | `category?` - filter by token category | | `get_color_palette` | Get the complete color palette | - | | `get_recipes` | Get component recipes with variants and default values | `name?` - filter by recipe name | | `get_patterns` | Get layout patterns with properties and usage examples | `name?` - filter by pattern name | | `get_conditions` | Get all conditions (breakpoints, pseudo-classes, color modes) | - | | `get_keyframes` | Get keyframe animations defined in the theme | - | | `get_text_styles` | Get text style compositions for typography | - | | `get_layer_styles` | Get layer style compositions for visual styling | - | | `get_animation_styles` | Get animation style compositions | - | | `get_config` | Get the resolved Panda CSS configuration | - | | `get_usage_report` | Analyze token/recipe usage across the codebase | `scope?` - `'all'`, `'token'`, `'recipe'` | The `get_usage_report` tool is particularly useful for auditing your design system, identifying unused tokens/recipes, and finding missing definitions. ## Configuration For most MCP clients, use this configuration: ```json { "mcpServers": { "panda": { "command": "npx", "args": ["-y", "@pandacss/mcp"] } } } ``` The server automatically loads your `panda.config.ts` from the current working directory when started. ### Claude Create `.mcp.json` in your project root: ```json { "mcpServers": { "panda": { "command": "npx", "args": ["-y", "@pandacss/mcp"] } } } ``` ### Cursor Create `.cursor/mcp.json`: ```json { "mcpServers": { "panda": { "command": "npx", "args": ["-y", "@pandacss/mcp"] } } } ``` ### VS Code Create `.vscode/mcp.json`: ```json { "servers": { "panda": { "command": "npx", "args": ["-y", "@pandacss/mcp"] } } } ``` ### Custom Config Path If your Panda config is not in the default location, specify it explicitly: ```json { "mcpServers": { "panda": { "command": "npx", "args": ["-y", "@pandacss/mcp", "--config", "./path/to/panda.config.ts"] } } } ``` ## Example Interactions Here are some example prompts you can use with AI assistants once MCP is configured: ### Exploring Tokens > "What spacing tokens are available?" The AI will use `get_tokens` with `category: "spacing"` to show you all spacing values. ### Understanding Recipes > "How do I use the button recipe with a destructive variant?" The AI will use `get_recipes` with `name: "button"` to show variants and usage. ### Finding Unused Tokens > "Which design tokens are not being used in my codebase?" The AI will use `get_usage_report` with `scope: "token"` to identify unused tokens. ### Checking Conditions > "What responsive breakpoints are defined?" The AI will use `get_conditions` to show all available breakpoints. ## Troubleshooting ### Server Not Starting If the MCP server fails to start: 1. Ensure Panda CSS is installed: `pnpm add -D @pandacss/dev` 2. Verify you have a valid `panda.config.ts` in your project 3. Check that `npx -y @pandacss/mcp` runs without errors ### Tools Not Available If tools aren't showing up in your AI assistant: 1. Restart the AI assistant after adding the MCP configuration 2. Verify the config file is in the correct location 3. Check the AI assistant's MCP documentation for any additional setup steps ### Usage Report Empty If `get_usage_report` returns empty results: 1. Ensure your `include` paths in `panda.config.ts` cover your source files 2. Run `pnpm panda codegen` to ensure the project is properly set up 3. Verify files contain Panda CSS usage (css(), styled(), etc.) --- ## Merging Styles Learn how to merge multiple styles without conflicts. ## Merging `css` objects You can merge multiple style objects together using the `css` function. ```js import { css } from 'styled-system/css' const style1 = { bg: 'red', color: 'white' } const style2 = { bg: 'blue' } const className = css(style1, style2) // => 'bg_blue text_white' ``` In some cases though, the style object might not be colocated in the same file as the component. In this case, you can use the `css.raw` function to preserve the original style object. > All `.raw(...)` signatures are identity functions that return the same value as the input, but serve as a hint to the > compiler that the value is a style object. ```js // style.js import { css } from 'styled-system/css' export const style1 = css.raw({ bg: 'red', color: 'white' }) // component.js import { css } from 'styled-system/css' import { style1 } from './style.js' const style2 = css.raw({ bg: 'blue' }) const className = css(style1, style2) // => 'bg_blue text_white' ``` ## Spreading `css.raw` objects > **Added in v1.6.1** You can also spread `css.raw` objects within style declarations. This is particularly useful for reusing styles in nested selectors, conditions, and complex compositions: ### Child selectors ```js import { css } from 'styled-system/css' const baseStyles = css.raw({ margin: 0, padding: 0 }) const component = css({ '& p': { ...baseStyles, fontSize: '1rem' }, '& h1': { ...baseStyles, fontSize: '2rem' } }) ``` ### Nested conditions ```js import { css } from 'styled-system/css' const interactive = css.raw({ cursor: 'pointer', transition: 'all 0.2s' }) const card = css({ _hover: { ...interactive, _dark: { ...interactive, color: 'white' } } }) ``` ## Merging `cva` + `css` styles The same technique can be used to merge an atomic `cva` recipe and a style object. ```js import { css, cx, cva } from 'styled-system/css' const overrideStyles = css.raw({ bg: 'red', color: 'white' }) const buttonStyles = cva({ base: { bg: 'blue', border: '1px solid black' }, variants: { size: { small: { fontSize: '12px' } } } }) const className = css( // returns the resolved style object buttonStyles.raw({ size: 'small' }), // add the override styles overrideStyles ) // => 'bg_red border_1px_solid_black color_white font-size_12px' ``` ## Merging `sva` + `css` styles The same technique can be used to merge an atomic `sva` recipe and a style object. ```js import { css, sva } from 'styled-system/css' const overrideStyles = css.raw({ bg: 'red', color: 'white' }) const buttonStyles = sva({ slots: ['root'] base: { root: { bg: 'blue', border: '1px solid black' } }, variants: { size: { root: { small: { fontSize: '12px' } } } } }) // returns the resolved style object for all slots const { root } = buttonStyles.raw({ size: 'small' }) const className = css( root, // add the override styles overrideStyles ) // => 'bg_red border_1px_solid_black color_white font-size_12px' ``` ## Merging config recipe and style object Due to the fact that the generated styles of a config recipe are saved in the `@layer recipe` cascade layer, they can be overridden with any atomic styles. Use the `cx` function to achieve that. > The `utilties` layer has more precedence than the `recipe` layer. ```js import { css, cx } from 'styled-system/css' import { button } from 'styled-system/recipes' const className = cx( // returns the resolved class name: `button button--size-small` button({ size: 'small' }), // add the override styles css({ bg: 'red' }) // => 'bg_red' ) // => 'button button--size-small bg_red' ``` ## Passing styles to custom components Expose `css`, a `*Css` prop, or `css.raw()` on a custom prop name. Panda extracts styles at the call site. > **Note:** Set `jsxFramework` in your config for JSX extraction. ```jsx const cardStyles = css.raw({ bg: 'red', color: 'white' }) function Card({ title, description, css: cssProp }) { return (

{title}

{description}

) } // usage ``` Props ending in `Css` work the same way, which is useful for named slots: ```jsx function Card({ title, description, rootCss, bodyCss }) { return (

{title}

{description}

) } ``` For any other prop name, wrap the value in `css.raw()`: ```jsx function Card({ title, description, style }) { return (

{title}

{description}

) } ``` See [custom component props](/docs/styling/style-props#custom-component-props). --- ## Migration strategy Run Panda alongside your current styling solution during a gradual migration, and what to know about how the two systems interact on the page. Most real migrations aren't a single rewrite, they're Panda and your current solution running on the same page for weeks or months while you convert one component or route at a time. This page covers what to know before you start that: how the two systems interact in the cascade, and a prompt you can hand to an AI coding agent to speed up the conversion itself. For the specifics of translating one particular tool's API to Panda's, jump straight to its guide: [Stitches](/docs/styling/stitches), [Styled Components](/docs/styling/styled-components), [Theme UI](/docs/styling/theme-ui), [Tailwind](/docs/styling/tailwind), [Chakra UI](/docs/styling/chakra-ui), [Emotion](/docs/styling/emotion), [StyleX](/docs/styling/stylex). ## The one thing that surprises people: layered vs. unlayered CSS Panda's generated CSS ships inside [cascade layers](/docs/styling/cascade-layers) (`@layer reset, base, tokens, recipes, utilities`). Per the CSS spec, **any unlayered rule beats every layered rule**, regardless of selector specificity or which stylesheet loaded last. Most existing CSS, plain stylesheets, most CSS-in-JS libraries, is unlayered. That means during a migration, your existing styles win over Panda's by default, even for a component you've already converted. If you see a converted component still showing its old styles, this is almost always why, not a specificity bug in your new Panda styles. Two ways to fix it, depending on which side you want to win: - **Let Panda's new styles win.** Strip the `@layer` wrapper from Panda's own output with [`postcss-cascade-layers`](/docs/styling/cascade-layers#polyfills). It emulates each layer's priority using specificity instead of the `@layer` rule, so Panda's CSS competes as unlayered CSS against your legacy styles instead of automatically losing to them. - **Keep your legacy styles as the fallback while you migrate.** Leave both as they are. Converted components need a specific enough legacy override removed (or the legacy selector deleted) once they're fully on Panda, since layering alone won't make Panda's version win. If your previous tool also uses cascade layers (rare, but check if you're coming from a tool that ships its own `@layer` rules), the fix is different: use [`layers`](/docs/reference/config#layers) to rename Panda's layers so they don't collide with the other tool's layer names, then declare both tools' `@layer` statements in one explicit order at the top of your CSS. Order in that declaration, not import order, decides priority between two layered sources. ## Migrating gradually, not all at once Pick one boundary and hold it consistently for the length of the migration, either by route, by component directory, or by team. Trying to convert overlapping pieces of the same component tree from two teams at once is where most of the cascade confusion above actually bites. A clean boundary also makes `git blame` and rollback straightforward if a converted piece needs to revert temporarily. ## AGENT PROMPT: converting a component to Panda Paste this into an AI coding agent along with the component file you want converted, filling in the tool you're migrating from: ```text You are converting a component from [STITCHES / STYLED-COMPONENTS / THEME UI / TAILWIND / CHAKRA UI / EMOTION / STYLEX] to Panda CSS. Follow these rules: 1. Read the migration guide at https://panda-css.com/docs/styling/[stitches|styled-components|theme-ui|tailwind| chakra-ui|emotion|stylex] first, and translate the component using the equivalents shown there, not general CSS knowledge. 2. Prefer the `css()` function for one-off styles, and `cva()`/`sva()` (defined with `styled-system/recipes` and `styled-system/patterns` imports) only when the component already has real variants, don't introduce variants that didn't exist in the original. 3. Map every raw color/spacing/font value in the original component to a design token from `styled-system/tokens` if an equivalent token exists. If none exists, leave the raw value and flag it in a comment rather than guessing at a token name. 4. Do not invent Panda config options, hooks, or CLI flags. If you're unsure whether something exists, say so instead of guessing. 5. Preserve the original component's props and behavior exactly, this is a styling migration, not a refactor. Don't rename props, change default variants, or restructure the component's JSX unless the styling approach requires it. 6. After converting, list anything you weren't able to translate directly (a CSS feature the old tool supported that Panda handles differently, a dynamic style that needs `css.raw()` or a data attribute instead) so a human can review it. ``` ## See also - [Cascade Layers](/docs/styling/cascade-layers) for the full layer model this page's coexistence advice is based on. - [Federated Micro-Frontends](/docs/design-systems/federated-microfrontends) if your migration also involves multiple independently-built bundles on the same page, a related but different collision problem. --- ## Using Next.js Easily use Panda with Next.js with our dedicated integration. Setting up Panda CSS with Next.js is straightforward. Follow the steps below to get started. If you don't have Next.js app installed, you can follow the [Create a Next.js app](#create-a-nextjs-app) section to create a new Next.js app, otherwise you can skip to the [Install Panda CSS](#install-panda-css) section. ## Start a new project You can chose between these two options to start a new project: ### Create a Next.js app First, create a Next.js app using the official [Create Next App](https://nextjs.org/docs/api-reference/create-next-app) CLI. We will name our project `test-app` but you can name it whatever you want. If you don't enter any parameter, the CLI will guide you through the process of creating a new Next.js app. {/* */} ```bash pnpm dlx create-next-app@latest --use-pnpm ``` ```bash npx create-next-app@latest --use-npm ``` ```bash yarn dlx create-next-app@latest --use-yarn ``` ```bash bunx create next-app@latest --use-bun ``` {/* */} You will be asked a few questions, answer them as follows: {/* */} ```bash βœ” What is your project named? … test-app βœ” Would you like to use TypeScript with this project? … Yes βœ” Would you like to use ESLint with this project? … Yes βœ” Would you like to use Tailwind CSS with this project? … No βœ” Would you like to use `src/` directory with this project? … Yes βœ” Use App Router (recommended)? … Yes βœ” Would you like to customize the default import alias? … No ``` {/* */} {/* */} ```bash βœ” What is your project named? … test-app βœ” Would you like to use TypeScript with this project? … Yes βœ” Would you like to use ESLint with this project? … Yes βœ” Would you like to use Tailwind CSS with this project? … No βœ” Would you like to use `src/` directory with this project? … Yes βœ” Use App Router (recommended)? … No βœ” Would you like to customize the default import alias? … No ``` {/* */} Enter the newly created directory: ```bash cd test-app ``` ### Install Panda CSS Install Panda CSS dependency using your favorite package manager. {/* */} ```bash pnpm install -D @pandacss/dev pnpm panda init --postcss ``` ```bash npm install -D @pandacss/dev npx panda init --postcss ``` ```bash yarn add -D @pandacss/dev yarn panda init --postcss ``` ```bash bun add -D @pandacss/dev bun panda init --postcss ``` {/* */} `panda init --postcss` command will automatically create a `postcss.config.cjs` file at the root of your project with the following code: ```js {3} module.exports = { plugins: { '@pandacss/dev/postcss': {} } } ``` For advanced configuration follow the Next.js PostCSS guide to set up a custom PostCSS configuration by referring to this [link](https://nextjs.org/docs/pages/building-your-application/configuring/post-css#customizing-plugins). ### Update package.json scripts Open your `package.json` file and update the `scripts` section as follows: ```diff {3} { "scripts": { + "prepare": "panda codegen", "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" } } ``` The `prepare` script that will run codegen after dependency installation. Read more about [codegen](/docs/reference/cli#codegen) in the CLI section. > This step ensures that the panda output directory is regenerated after each dependency installation. So you can add > the output directory to your `.gitignore` file and not worry about it. ### Configure the content Make sure that all of the paths of your React components are included in the `include` section of the `panda.config.ts` file. ```ts {7} filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ // Whether to use css reset preflight: true, // Where to look for your css declarations include: ['./src/components/**/*.{ts,tsx,js,jsx}', './src/app/**/*.{ts,tsx,js,jsx}'], // Files to exclude exclude: [], // The output directory for your css system outdir: 'styled-system' }) ``` ```ts {7} filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ // Whether to use css reset preflight: true, // Where to look for your css declarations include: ['./src/components/**/*.{ts,tsx,js,jsx}', './src/pages/**/*.{ts,tsx,js,jsx}'], // Files to exclude exclude: [], // The output directory for your css system outdir: 'styled-system' }) ``` ### Configure the entry CSS with layers In your Next.js project, navigate to the `src/app` folder and open `globals.css` file. Replace all the content with the following code: In your Next.js project, navigate to the `src/styles` folder and open `globals.css` file. Replace all the content with the following code: ```css @layer reset, base, tokens, recipes, utilities; ``` > **Note:** Feel free to remove the `page.module.css` file as we don't need it anymore. > **Note:** Feel free to remove the `Home.module.css` file as we don't need it anymore. ### Import the entry CSS in your app Make sure that you import the `globals.css` file in your `src/app/layout.tsx` file as follows: ```tsx {1} filename="./src/app/layout.tsx" import './globals.css' import type { Metadata } from 'next' import localFont from 'next/font/local' const geistSans = localFont({ src: './fonts/GeistVF.woff', variable: '--font-geist-sans', weight: '100 900' }) const geistMono = localFont({ src: './fonts/GeistMonoVF.woff', variable: '--font-geist-mono', weight: '100 900' }) export const metadata: Metadata = { title: 'Create Next App', description: 'Generated by create next app' } export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { return ( {children} ) } ``` Make sure that you import the `globals.css` file in your `src/pages/_app.tsx` file as follows: ```tsx {1} filename="./src/pages/_app.tsx" import '../styles/globals.css' import type { AppProps } from 'next/app' export default function App({ Component, pageProps }: AppProps) { return } ``` ### Start using Panda We will update the contents of `src/app/page.tsx` with the following snippet that uses Panda CSS: We will update the contents of `src/pages/index.tsx` with the following snippet that uses Panda CSS: ```tsx import { css } from '../../styled-system/css' export default function Home() { return
Hello 🐼!
} ``` ### Start the development server Run the following command to start the development server: {/* */} ```bash pnpm dev ``` ```bash npm run dev ``` ```bash yarn dev ``` ```bash bun dev ``` {/* */} Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
## Troubleshooting ### I don't see any styles Sometimes Next.js caches PostCSS generated styles and when that happens you need to clear the cache. To do that, delete the `.next` folder and restart your development server. You can also update you `package.json` scripts to delete the `.next` folder before each build: ```diff {3,4} { "scripts": { - "dev": "next dev", + "dev": "rm -rf .next && next dev", }, } ``` This is a known issue with Next.js and you can track the progress here: - [vercel/next.js#39410](https://github.com/vercel/next.js/issues/39410) - [vercel/next.js#48748](https://github.com/vercel/next.js/issues/48748) - [vercel/next.js#47533](https://github.com/vercel/next.js/issues/47533) ### I don't see any import autocomplete in my IDE If you're not getting import autocomplete in your IDE, you may need to include the `styled-system` directory in your `tsconfig.json` file: ```json filename="tsconfig.json" { // ... "include": ["src", "styled-system"] } ``` ### Codegen fails using es5 If you run into any error related to "Transforming const to the configured target environment ("es5") is not supported yet", update your tsconfig to use es6 or higher: ```json filename="tsconfig.json" { "compilerOptions": { "target": "es6" } } ``` --- ## Using Nuxt Easily use Panda with Nuxt with the vue integration. Learn how to set up Panda CSS in a Nuxt project using PostCSS. ## Start a new project ### Create Nuxt project To get started, we will need to create a new Nuxt project using npx. {/* */} ```bash npx nuxi@latest init test-app ``` ```bash pnpm dlx nuxi@latest init test-app ``` ```bash bunx nuxi@latest init test-app ``` {/* */} Enter the newly created directory and install the dependencies. {/* */} ```bash cd test-app pnpm install ``` ```bash cd test-app npm install ``` ```bash cd test-app yarn install ``` ```bash cd test-app bun install ``` {/* */} ### Install Panda Install panda and create your `panda.config.ts` file. {/* */} ```bash pnpm install -D @pandacss/dev pnpm panda init ``` ```bash npm install -D @pandacss/dev npx panda init ``` ```bash yarn add -D @pandacss/dev yarn panda init ``` ```bash bun add -D @pandacss/dev bun panda init ``` {/* */} ### Update package.json scripts Open your `package.json` file and update the `scripts` section as follows: ```diff {3} filename="package.json" { "scripts": { + "prepare": "panda codegen", "build": "nuxt build", "dev": "nuxt dev", "generate": "nuxt generate", "preview": "nuxt preview" } } ``` - `"prepare"` - script that will run Panda CSS CLI codegen before each build. Read more about [codegen](/docs/reference/cli#codegen) in the CLI section. > This step ensures that the panda output directory is regenerated after each dependency installation. So you can add > the output directory to your `.gitignore` file and not worry about it. ### Configure the content Make sure that all of the paths of your Vue components are included in the `include` section of the `panda.config.ts` file. ```js {8,17} filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ // Whether to use css reset preflight: true, // Where to look for your css declarations include: ['./app.vue', './components/**/*.{js,jsx,ts,tsx,vue}', './pages/**/*.{js,jsx,ts,tsx,vue}'], // Files to exclude exclude: [], // The output directory for your css system outdir: 'styled-system' }) ``` ### Configure the entry CSS with layers Add this code to an `assets/css/global.css` file. ```css filename="assets/css/global.css" @layer reset, base, tokens, recipes, utilities; ``` ### Configure Nuxt Add the following configuration to the `nuxt.config.ts` file ```js {1-2,5-17} filename="nuxt.config.ts" import { createResolver } from '@nuxt/kit' const { resolve } = createResolver(import.meta.url) export default defineNuxtConfig({ alias: { 'styled-system': resolve('./styled-system') }, css: ['@/assets/css/global.css'], postcss: { plugins: { '@pandacss/dev/postcss': {} } } }) ``` With the above we've performed the following: - imported the global css file '@/assets/css/global.css' at the root of the system. - created an alias that points to the `styled-system` directory. - added panda into the postcss plugins section. ## Start your build process Run the following command to start your development server. {/* */} ```bash pnpm dev ``` ```bash npm run dev ``` ```bash yarn dev ``` ```bash bun dev ``` {/* */} ### Start using Panda Now you can start using Panda CSS in your project. As an example here is a snippet of code for a `components/Demo.vue` file. ```xml filename="components/Demo.vue" ``` --- ## Patterns Patterns are layout primitives that can be used to create robust and responsive layouts with ease. Panda comes with predefined patterns like stack, hstack, vstack, wrap, etc. These patterns can be used as functions or JSX elements. Think of patterns as a set of predefined styles to reduce repetition and improve readability. You can override the properties as needed, just like in the `css` function. ## Creating Patterns To learn how to create patterns, check out the [customization](/docs/design-systems/patterns) section. ## Predefined Patterns ### Box The Box pattern does not contain any additional styles. With its function form it's the equivalent of the `css` function. It can be useful with its JSX form and is the equivalent of a `styled.div` component, serving mostly to get style props available in JSX. ```tsx import { Box } from '../styled-system/jsx' function App() { return (
Cool !
) } ``` ### Container The Container pattern is used to create a container with a max-width and center the content. By default, the container sets the following properties: - `maxWidth: 8xl` - `marginX: auto` - `position: relative` - `paddingX: { base: 4, md: 6, lg: 8 }` ```tsx import { container } from '../styled-system/patterns' function App() { return (
First
Second
Third
) } ```
```tsx import { Container } from '../styled-system/jsx' function App() { return (
First
Second
Third
) } ```
### Stack The Stack pattern is a layout primitive that can be used to create a vertical or horizontal stack of elements. The `stack` function accepts the following properties: - `direction`: An alias for the css `flex-direction` property. Default is `column`. - `gap`: The gap between the elements in the stack. Default is `8px`. - `align`: An alias for the css `align-items` property. - `justify`: An alias for the css `justify-content` property. Change defaults in [config](/docs/design-systems/patterns#changing-pattern-defaults). `HStack` and `VStack` are separate patterns with their own defaults. ```tsx import { stack } from '../styled-system/patterns' function App() { return (
First
Second
Third
) } ```
```tsx import { Stack } from '../styled-system/jsx' function App() { return (
First
Second
Third
) } ```
#### HStack The HStack pattern is a wrapper around the `stack` pattern that sets the `direction` property to `horizontal`, and centers the elements vertically. ```tsx import { hstack } from '../styled-system/patterns' function App() { return (
First
Second
Third
) } ```
```tsx import { HStack } from '../styled-system/jsx' function App() { return (
First
Second
Third
) } ```
#### VStack The VStack pattern is a wrapper around the `stack` pattern that sets the `direction` property to `vertical`, and centers the elements horizontally. ```tsx import { vstack } from '../styled-system/patterns' function App() { return (
First
Second
Third
) } ```
```tsx import { VStack } from '../styled-system/jsx' function App() { return (
First
Second
Third
) } ```
### Wrap The Wrap pattern is used to add space between elements and wraps automatically if there isn't enough space. The `wrap` function accepts the following properties: - `gap`: The gap between the elements in the stack. - `columnGap`: The gap between the elements in the stack horizontally. - `rowGap`: The gap between the elements in the stack vertically. - `align`: An alias for the css `align-items` property. - `justify`: An alias for the css `justify-content` property. ```tsx import { wrap } from '../styled-system/patterns' function App() { return (
First
Second
Third
) } ```
```tsx import { Wrap } from '../styled-system/jsx' function App() { return (
First
Second
Third
) } ```
### Aspect Ratio The Aspect Ratio pattern is used to create a container with a fixed aspect ratio. It is used when displaying images, maps, videos and other media. > **Note:** In most cases, we recommend using the `aspectRatio` property instead of the pattern. The `aspectRatio` function accepts the following properties: - `ratio`: The aspect ratio of the container. Can be a number or a string. ```tsx import { aspectRatio } from '../styled-system/patterns' function App() { return (