# Panda CSS Guides > This document contains all guides documentation for Panda CSS ## Table of Contents - [Using Panda in a Component Library](#using-panda-in-a-component-library) - [Debugging](#debugging) - [Dynamic styling](#dynamic-styling) - [Federated Micro-Frontends](#federated-micro-frontends) - [Custom Font](#custom-font) - [Minimal Setup](#minimal-setup) - [Multi-Theme Tokens](#multi-theme-tokens) - [Static CSS Generator](#static-css-generator) --- ## Using Panda in a Component Library How to set up Panda in a component library When creating a component library that uses Panda which can be used in a variety of different projects, you have four options: 1. Ship a Panda [preset](/docs/customization/presets) 2. Ship a static CSS file 3. Use Panda as external package, and ship the src files 4. Use Panda as external package, and ship the build info file > In the examples below, we use `tsup` as the build tool. You can use any other build tool. ## Recommendations - If your library code shouldn't be published on npm and App code uses Panda, use [ship build info](#ship-the-build-info-file) approach - If your app code doesn't use Panda, use the [static css](#ship-a-static-css-file) file approach - If your app code lives in a monorepo, use the [include src files](#include-the-src-files) approach - If your library code doesn't ship components but only ships tokens, patterns or recipes, use the [ship preset](#ship-a-panda-preset) approach > âš ī¸ If you use the `include src files` or `ship build info` approach, you might also need to ship a `preset` if your > library code has any custom tokens, patterns or recipes. ## Ship a Panda Preset This is the simplest approach. You can include the token, semantic tokens, text styles, etc. within a preset and consume them in your projects. **Library code** ```tsx filename="src/index.ts" import { definePreset } from '@pandacss/dev' export const acmePreset = definePreset({ theme: { extend: { tokens: { colors: { primary: { value: 'blue.500' } } } } } }) ``` Build the preset code ```bash pnpm tsup src/index.ts ``` **App code** ```tsx filename="panda.config.ts" import { acmePreset } from '@acme-org/panda-preset' import { defineConfig } from '@pandacss/dev' export default defineConfig({ //... presets: ['@pandacss/dev/presets', acmePreset] }) ``` > Adding a preset will remove the default theme from Panda. To add it back, you need to include the > `@pandacss/dev/presets` preset. ## Ship a Static CSS File This approach involves extracting the static css of your library at build time. Then you can import the CSS file in your app code. **Library code** ```tsx filename="src/index.tsx" import { css } from '../styled-system/css' export function Button({ children }) { return ( ) } ``` Then you can build the library code and generate the static CSS file: ```bash # build the library code tsup src/index.tsx # generate the static CSS file panda cssgen --outfile dist/styles.css ``` Finally, don't forget to include the [cascade layers](/docs/concepts/cascade-layers) as well in your app code: **App code** ```tsx filename="src/App.tsx" import { Button } from '@acme-org/design-system' import './main.css' export function App() { return } ``` **main.css** ```css filename="src/main.css" @layer reset, base, tokens, recipes, utilities; @import url('@acme-org/design-system/dist/styles.css'); /* Your own styles here */ ``` This approach comes with a few downsides: - You can't customize the styles since the css is already generated - You might need add the [prefix](/docs/references/config#prefix) option to avoid className conflicts ```tsx filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ //... prefix: 'acme' }) ``` - You might have duplicate CSS classes when using multiple atomic css libraries ## Use Panda as external package ### Summary - create a Panda [preset](/docs/customization/presets) so that you (and your users) can share the same design system tokens - create a workspace package for your outdir (`@acme-org/styled-system`) and use that package name as the `importMap` in your app code - have your component library (`@acme-org/components`) use the `@acme-org/styled-system` package as external --- Let's make a dedicated workspace package for your `outdir`: 1. Create a new directory `packages/styled-system` (or any other name) 2. Install `@pandacss/dev` as a dev dependency 3. Run the `panda init` command in there to generate a `panda.config.ts` file, don't forget to set the `jsxFramework` if needed 4. [optional] you might want to install and import your [preset](/docs/customization/presets) in this `panda.config.ts` file as well 5. Run the [`panda emit-pkg`](/docs/references/cli#emit-pkg) command to set the entrypoints in [`exports`](https://nodejs.org/api/packages.html#exports) This should look similar to this: ```json { "name": "@acme-org/styled-system", "version": "1.0.0", "exports": { "./css": { "types": "./css/index.d.ts", "require": "./css/index.mjs", "import": "./css/index.mjs" }, "./tokens": { "types": "./tokens/index.d.ts", "require": "./tokens/index.mjs", "import": "./tokens/index.mjs" }, "./types": { "types": "./types/index.d.ts", "require": "./types/index.mjs", "import": "./types/index.mjs" }, "./patterns": { "types": "./patterns/index.d.ts", "require": "./patterns/index.mjs", "import": "./patterns/index.mjs" }, "./recipes": { "types": "./recipes/index.d.ts", "require": "./recipes/index.mjs", "import": "./recipes/index.mjs" }, "./jsx": { "types": "./jsx/index.d.ts", "require": "./jsx/index.mjs", "import": "./jsx/index.mjs" }, "./styles.css": "./styles.css" }, "devDependencies": { "@pandacss/dev": "^1.4.2", "@types/react": "19.2.2", "react": "^19.2.0" }, "peerDependencies": { "react": ">=19" } } ``` > Notice that we've included the `react` and its corresponding `@types/react` in the `devDependencies` and > `peerDependencies`. This is to ensure the types are correctly set up in the `styled-system` package. Going forward, you'll now import the functions from the `@acme-org/styled-system` monorepo package. ```tsx import { css } from '@acme-org/styled-system/css' export function Button({ children }) { return ( ) } ``` **App code** Install the newly created `@acme-org/styled-system` package in your app code. ```bash pnpm add @acme-org/styled-system ``` Configure the `importMap` in your `panda.config.ts` to match the `name` field of your outdir `package.json`. This will inform Panda which imports belong to the `styled-system`. ```tsx filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ //... importMap: '@acme-org/styled-system', outdir: 'styled-system' }) ``` Mark the `@acme-org/styled-system` as an external package in your library build tool. This ensures that the generated JS runtime code is imported only once, avoiding duplication. ```bash tsup src/index.tsx --external @acme-org/styled-system ``` ### Include the src files Include the `src` directory from the library code in the panda config. ```tsx {6} filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ //... include: ['../@acme-org/design-system/src/**/*.tsx', './src/**/*.{ts,tsx}'], importMap: '@acme-org/styled-system', outdir: 'styled-system' }) ``` ### Ship the build info file This approach is similar to the previous one, but instead of shipping the source code, you ship the Panda build info file. This will have **the exact same end-result** as adding the sources files in the `include`, but it will allow you not to ship the source code. The build info file is a JSON file that **only** contains the information about the static extraction result, you still need to ship your app build/dist by yourself. It can be used by Panda to generate CSS classes without the need for parsing the source code. Generate the build info file: ```bash panda ship --outfile dist/panda.buildinfo.json ``` **App code** Install the newly created `@acme-org/styled-system` package in your app code. ```bash pnpm add @acme-org/styled-system ``` Configure the `importMap` in your `panda.config.ts` to match the `name` field of your outdir `package.json`. This will inform Panda which imports belong to the `styled-system`. ```tsx filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ //... importMap: '@acme-org/styled-system', outdir: 'styled-system' }) ``` Will allow imports like: ```tsx import { css } from '@acme-org/styled-system/css' import { button } from '@acme-org/styled-system/recipes' ``` Next, you need to include the build info file from the library code in the panda config. ```tsx {6} filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ //... include: ['./node_modules/@acme-org/design-system/dist/panda.buildinfo.json', './src/**/*.{ts,tsx}'], importMap: '@acme-org/styled-system', outdir: 'styled-system' }) ``` ## FAQ ### Why should my component library use an external package `styled-system`? By de-coupling the component library from the `styled-system`, your users can share the same runtime code between your library and their app code. ```tsx filename="component-lib/src/button.tsx" import { css } from '@acme-org/styled-system/css' export function Button({ children, css: cssProp }) { return ( ) } ``` ```tsx filename="app/src/App.tsx" import { Button } from '@acme-org/design-system' import { css } from '@acme-org/styled-system/css' export function App() { return } ``` Marking the `styled-system` as an external package in your build tool means that the generated JS runtime code (the `css` function is the example above) is imported only once, avoiding duplication. ### How do I use the `@acme-org/styled-system` package ? You can use your monorepo workspace package `@acme-org/styled-system` just like any other dependency in your app or component library code. ```bash pnpm add @acme-org/styled-system ``` Set the `importMap` in your `panda.config.ts` to that same package name. This will inform Panda which imports belong to the `styled-system`. ```tsx filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ //... importMap: '@acme-org/styled-system' }) ``` Then you can import the functions from the `@acme-org/styled-system` monorepo package. ```tsx import { css } from '@acme-org/styled-system/css' export function Button({ children }) { return ( ) } ``` ### How to override tokens used by the `@acme-org/styled-system` package? You can override the tokens used by the `@acme-org/styled-system` package by extending the `theme` in your `panda.config.ts` file. ```tsx filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' export default defineConfig({ //... presets: ['@acme-org/preset'] theme: { extend: { tokens: { colors: { primary: { value: 'blue.500' } } } } } }) ``` ## Troubleshooting - When using `tsup` or any other build tool for your component library, if you run into a module resolution error that looks similar to `ERROR: Could not resolve "../styled-system/xxx"`. Consider setting the `outExtension`in the panda config to`js` - If you use Yarn PnP, you might need to set the `nodeLinker: node-modules` in the `.yarnrc.yml` file. --- ## Debugging How can I debug my styles or profile the extraction process? ## panda debug Panda's built-in debug command helps you see which files are processed, what styles are generated, and your final config. By default it will scan and output debug files for the entire project depending on your `include` and `exclude` options from your config file. {/* */} ```bash pnpm panda debug # You can also debug a specific file or folder # using the optional glob argument pnpm panda debug src/components/Button.tsx pnpm panda debug "./src/components/**" ``` ```bash npx panda debug # # You can also debug a specific file or folder # using the optional glob argument npx panda debug src/components/Button.tsx npx panda debug "./src/components/**" ``` ```bash yarn panda debug # # You can also debug a specific file or folder # using the optional glob argument yarn panda debug src/components/Button.tsx yarn panda debug "./src/components/**" ``` ```bash bun panda debug # # You can also debug a specific file or folder # using the optional glob argument bun panda debug src/components/Button.tsx bun panda debug "./src/components/**" ``` {/* */} This would generate a `debug` folder in your `config.outdir` folder with the following structure: The `config.json` file will contain the resolved config result, meaning the output after merging config presets in your own specific options. It can be useful to check if your config contains everything you expect for your app to be working, such as tokens or recipes. `*.ast.json` files will look like: ```json [ { "name": "css", "type": "object", "data": [ { "transitionProperty": "all", "opacity": "0.5", "border": "1px solid", "borderColor": "black", "color": "gray.600", "_hover": { "color": "gray.900" }, "rounded": "md", "p": "1.5", "_dark": { "borderColor": "rgba(255, 255, 255, 0.1)", "color": "gray.400", "_hover": { "color": "gray.50" } } } ], "kind": "CallExpression", "line": 13, "column": 9 } ] ``` And the `.css` file associated would just contain the styles generated from the extraction process on that file only. ## PANDA_DEBUG env variable You can prefix any of the Panda CLI command with the `PANDA_DEBUG` environment variable to show debug logs. ```bash PANDA_DEBUG=* pnpm panda ``` This can be useful to check if a specific file is being processed or not, or if a specific function/component has been extracted. ``` ❯ PANDA_DEBUG=* pnpm panda cssgen đŸŧ debug [config:path] /Users/astahmer/dev/open-source/panda-clone/website/panda.config.ts đŸŧ debug [ast:import] Found import { css } in /Users/astahmer/dev/open-source/panda-clone/website/theme.config.tsx đŸŧ debug [ast:Icon] { kind: 'component' } đŸŧ debug [ast:css] { kind: 'function' } đŸŧ debug [hrtime] Parsed /Users/astahmer/dev/open-source/panda-clone/website/theme.config.tsx (9.66ms) đŸŧ debug [ast:import] Found import { css } in /Users/astahmer/dev/open-source/panda-clone/website/src/DEFAULT_THEME.tsx đŸŧ debug [ast:DiscordIcon] { kind: 'component' } đŸŧ debug [ast:css] { kind: 'function' } đŸŧ debug [ast:Anchor] { kind: 'component' } đŸŧ debug [ast:GitHubIcon] { kind: 'component' } đŸŧ debug [ast:Flexsearch] { kind: 'component' } đŸŧ debug [ast:MatchSorterSearch] { kind: 'component' } đŸŧ debug [hrtime] Parsed /Users/astahmer/dev/open-source/panda-clone/website/src/DEFAULT_THEME.tsx (4.51ms) đŸŧ debug [ast:import] No import found in /Users/astahmer/dev/open-source/panda-clone/website/src/constants.tsx đŸŧ debug [hrtime] Parsed /Users/astahmer/dev/open-source/panda-clone/website/src/constants.tsx (4.23ms) đŸŧ debug [ast:import] Found import { css } in /Users/astahmer/dev/open-source/panda-clone/website/src/index.tsx đŸŧ debug [ast:css] { kind: 'function' } ``` ## Performance profiling If Panda is taking too long to process your files, you can use the `--cpu-prof` with the `panda`, `panda cssgen`, `panda codegen` and `panda debug` commands to generate a flamegraph of the whole process, which will allow you (or us as maintainers) to see which part of the process is taking the most time. This will generate a `panda-{command}-{timestamp}.cpuprofile` file in the current working directory, which can be opened in tools like [Speedscope](https://www.speedscope.app/) ```bash pnpm panda --cpu-prof ``` ## FAQ ### Why are my styles not applied? Check that the [`@layer` rules](/docs/concepts/cascade-layers#layer-css) are set and the corresponding `.css` file is included. [If you're not using `postcss`](/docs/installation/cli), ensure that `styled-system/styles.css` is imported and that the `panda` command has been run (or is running with `--watch`). ### Some CSS is missing when using absolute imports This can happen when `tsconfig` (with `paths` or `baseUrl`) or with package.json [`#imports`](https://nodejs.org/api/packages.html#subpath-imports). Panda tries to automatically infer and read the custom paths defined in `tsconfig.json` file. However, there might be scenarios that won't work. To fix this add the `importMap` option to your `panda.config.js` file, setting it's value to match the way you import the `outdir` modules. ```app.tsx // app.tsx import { css } from "~/styled-system/css" // tsconfig.json paths // -> importMap: "~/styled-system" import { css } from "styled-system/css" // tsconfig.json baseUrl // -> importMap: "styled-system" import { css } from "@my-monorepo/ui-kit/css" // monorepo workspace package // -> importMap: "@my-monorepo/ui-kit" import { css } from "#styled-system/css" // package.json#imports // -> importMap: "#styled-system ``` ```js // panda.config.js export default defineConfig({ importMap: '~/styled-system' }) ``` This will ensure that the paths are resolved correctly, and HMR works as expected. --- ### 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. ### 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. --- ## The postcss plugin sometimes seems slow or runs too frequently This is mostly specific to the host bundler (`vite`, `webpack` etc) you're using, it is up to them to decide when to run the postcss plugin again, and sometimes it can be more than needed for your usage. We do our best to cache the results of the postcss plugin by checking if the filesystem or your config have actually changed, but sometimes it might not be enough. In those rare cases, you might want to swap to using the [CLI](/docs/installation/cli) instead, as it will always be more performant than the postcss alternative since we directly watch for filesystem changes and only run the extract/codegen steps when needed. If you want to keep the convenience of having just one command to run, you can use something like `concurrently` for that: ```json file="package.json" { "scripts": { "dev": "concurrently \"next dev\" \"panda --watch\"" } } ``` --- ## 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/guides/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, you need to use the `size` prop. ### 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
``` Elements outside `.acme-v1-scope` won't resolve `--acme-v1-colors-brand`. Useful when multiple remotes share a host page but each remote's tokens should be contained to its own DOM subtree. `cssVarRoot` is optional. `prefix` alone is sufficient for most federated setups because the variable names already differ per version. ## How `defineRecipe` and `cva` are affected Both recipe APIs benefit from `prefix`, in slightly different ways. `defineRecipe` emits a stable class name based on the recipe name (`.button`, `.button--size-lg`). Without `prefix`, two versions of the same recipe produce identical class names with different declarations. With `prefix`, each version emits its own namespaced class — `acme-v1-button`, `acme-v2-button` — and the collision is gone. `cva` with raw values is already collision-free: ```tsx filename="src/Button.tsx" import { cva } from '../styled-system/css' const button = cva({ base: { background: '#ea580c', padding: '8px 12px' } }) // emits .bg_\#ea580c .p_8px_12px ... ``` The atomic class names encode the **value**, so two versions with different values naturally produce different class names. `prefix` adds a second layer of isolation but isn't strictly required here. `cva` with semantic tokens is the quiet case: ```tsx const button = cva({ base: { background: 'brand' } }) // emits .bg_brand { background: var(--colors-brand) } ``` The atomic class name is **stable** across versions (`bg_brand` in both, with identical rule body), so there's no class-name clash. But both versions declare `--colors-brand` on `:root` with different values — the cascade picks one globally, and the visual result is wrong even though the class names matched. `prefix` fixes this by namespacing both the class (`acme-v1-bg_brand`) and the variable (`--acme-v1-colors-brand`). ## Recommended remote config For a Panda lib intended to ship into a federated host: ```ts filename="panda.config.ts" import { defineConfig } from '@pandacss/dev' import pkg from './package.json' assert { type: 'json' } const major = pkg.version.split('.')[0] const slug = pkg.name.replace(/[@/]/g, '-').replace(/^-/, '') export default defineConfig({ prefix: `${slug}-v${major}`, preflight: false, jsxFramework: 'react', outdir: 'styled-system', theme: { extend: { // tokens, recipes, etc. } } }) ``` > **Note:** `preflight: false` is recommended for libs and remotes. A reset > stylesheet shipped from a remote can stomp on the host's body styles. > Let the host own the reset. ## Model 2: Library ships build info + preset Everything above assumes the lib publishes prebuilt CSS. The other shape is [shipping build info](/docs/guides/component-library#ship-the-build-info-file) and a preset: each consuming remote generates the final stylesheet during its own build. The collision is identical, and `prefix` is still the fix — it just moves to the **consumer's** config, keyed to the remote's identity rather than the DS version. `panda ship` only writes extraction results (which styles are used), not the token and recipe **definitions**. So a build-info consumer wires up two pieces: the build-info file (via `include`) and the lib's preset (via `presets`). The preset supplies the definitions, the build-info file supplies the usage. `prefix` lives on the consumer's top-level config and is applied at emission, so `.button` becomes `.remote1-button` and `--colors-brand` becomes `--remote1-colors-brand` — regardless of whether the definition came from the remote's own source or from the lib's preset. ```ts filename="remote1/panda.config.ts" import { defineConfig } from '@pandacss/dev' import { acmeDsPreset } from '@acme-org/design-system' export default defineConfig({ prefix: 'remote1', presets: ['@pandacss/dev/presets', acmeDsPreset], importMap: '@acme-org/styled-system', include: [ './node_modules/@acme-org/design-system/dist/panda.buildinfo.json', './src/**/*.{ts,tsx}' ] }) ``` ### Cross-version isolation is automatic Because the prefix is keyed to the remote — not to the DS version — version isolation falls out without anyone tracking versions. If `remote1` pins `@acme-org/design-system@29` and `remote2` pins `@30`, each remote resolves its own copy in `node_modules`, gets its own preset plus build info, and emits CSS under its own remote prefix: ```css /* remote1's bundle (DS v29) */ .remote1-button { ... } :where(:root, :host) { --remote1-colors-brand: #ea580c; } /* remote2's bundle (DS v30) */ .remote2-button { ... } :where(:root, :host) { --remote2-colors-brand: #2563eb; } ``` Two payloads can't collide on a selector or variable name, so the host page loads both without a fight. > **Note:** In the build-info model the lib never sets a `prefix` — each > consumer namespaces itself. A lib that baked in its own prefix would force > every consumer to share it, which puts back the collision you set out to > avoid. ## Verifying the output After running `panda cssgen`, grep the emitted bundle for the names that previously collided: ```bash grep -E "^\.button|--colors-brand:" styled-system/styles.css ``` You should see every match carrying your prefix: ```css .acme-v1-button { ... } :where(:root, :host) { ... --acme-v1-colors-brand: ...; ... } ``` If you see unprefixed matches, double-check that `prefix` is set at the **top level** of `defineConfig` (not nested inside `theme`), and regenerate the bundle. ## Limits of `prefix` `prefix` solves the structural class-name and CSS-variable collisions for multi-version federated setups. It does not solve: - **Same-prefix collisions.** Two libs that both choose `prefix: 'design'` collide as if neither had a prefix. The prefix string is your isolation key — choose it like you'd choose a package name. - **Reset collisions.** If multiple remotes ship `preflight: true`, the resets fight regardless of `prefix` because they target raw element selectors. Set `preflight: false` on remotes. - **Hand-written CSS.** `prefix` operates on what Panda emits. CSS authored outside Panda still uses your hand-written selectors. For total style isolation against an untrusted host, consider wrapping the remote in an iframe or Shadow DOM. Heavier-weight, but bulletproof. ## Related - [Cascade Layers](/docs/concepts/cascade-layers) — solves single-version override leakage - [Hashing](/docs/concepts/writing-styles#hashing) — alternative to prefix when you want short opaque class names instead of namespace strings - [Component Library](/docs/guides/component-library) — distribution patterns for shipping a Panda lib - [Presets](/docs/customization/presets) — sharing tokens and recipes across consumers --- ## Custom Font How to use custom fonts in your project. Adding custom fonts to your application or website is a typical requirement for projects. Panda recommends using custom fonts through CSS variables for consistency. ## Setup ### Next.js Next.js provides a built-in automatic self-hosting for any font file by using the `next/font` module. It allows you to conveniently use all Google Fonts and any local font with performance and privacy in mind. Here's an example of how to load a local "Mona Sans" font and a Google Font "Fira Code" in your Next.js project. ```js filename="styles/font.ts" import { Fira_Code } from 'next/font/google' import localFont from 'next/font/local' export const MonaSans = localFont({ src: '../fonts/Mona-Sans.woff2', display: 'swap', variable: '--font-mona-sans' }) export const FiraCode = Fira_Code({ weight: ['400', '500', '700'], display: 'swap', subsets: ['latin'], variable: '--font-fira-code' }) ``` > Ideally, you should load the font in the layout file. Next, you need to add the font variables to your HTML document. You can do this using either the App Router or the Pages Router. #### App Router ```jsx filename="app/layout.tsx" import { FiraCode, MonaSans } from '../styles/font' export default function Layout(props) { const { children } = props return ( {children} ) } ``` > **Note 🚨:** By default, Next.js attaches the className for the fonts to the `` element, for panda to > appropriately load fonts, update the code to attach the `className` to the `` element. #### Pages Router ```jsx filename="pages/_app.tsx" import { FiraCode, MonaSans } from '../styles/font' export default function App({ Component, pageProps }) { return ( <> ) } ``` ### Fontsource [Fontsource](https://fontsource.org/) streamlines the process of integrating fonts into your web application. To begin, install your desired font package: ```bash pnpm add @fontsource-variable/fira-code ``` Next, import the font into your project: ```jsx import '@fontsource-variable/fira-code' ``` Lastly, create a variable to use it as a token in the panda config ```css filename="styles/font.css" :root { --font-fira-code: 'Fira Code Variable', monospace; } ``` ### Vanilla CSS You can leverage the native font-face CSS property to load custom fonts in your project. ```css @font-face { font-family: 'Mona Sans'; src: url('../fonts/Mona-Sans.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; } ``` Then alias the font names to css variables. ```css :root { --font-mona-sans: 'Mona Sans', sans-serif; } ``` ### Global Font Face You can also define global font face in your panda config. ```js export default defineConfig({ globalFontface: { Fira: { src: 'url(/fonts/fira.woff2) format("woff2")', fontWeight: 400, fontStyle: 'normal', fontDisplay: 'swap' } } }) ``` You can also define multiple font sources for the same weight. ```js export default defineConfig({ globalFontface: { Fira: { src: ['url(/fonts/fira.woff2) format("woff2")', 'url(/fonts/fira.woff) format("woff")'], fontWeight: 400, fontStyle: 'normal', fontDisplay: 'swap' } } }) ``` You can also define multiple font weights. ```js export default defineConfig({ globalFontface: { Fira: [ { src: 'url(/fonts/fira.woff2) format("woff2")', fontWeight: 400, fontStyle: 'normal', fontDisplay: 'swap' }, { src: 'url(/fonts/fira-bold.woff2) format("woff2")', fontWeight: 700, fontStyle: 'normal', fontDisplay: 'swap' } ] } }) ``` Then expose the font names to css variables. ```css :root { --font-fira-code: 'Fira Code Variable', monospace; } ``` You can also use [globalVars](/docs/concepts/writing-styles#global-vars) in your panda config to define the variables. ```js export default defineConfig({ globalVars: { '--font-fira-code': 'Fira Code Variable, monospace' } }) ``` ## Update Panda Config ```js export default defineConfig({ theme: { extend: { tokens: { fonts: { fira: { value: 'var(--font-fira-code), Menlo, monospace' }, mona: { value: 'var(--font-mona-sans), sans-serif' } } } } } }) ``` ## Use the custom fonts ```jsx import { css } from '../styled-system/css' function Page() { return (

Mona Sans

Fira Code
) } ``` --- ## Minimal Setup How to set up Panda with the bare minimum. The default Panda setup includes utilities and design tokens by default. In this guide, you'll see how to strip out the defaults and start from scratch. ## Removing default tokens To remove the default design tokens injected by Panda, set the `presets` key to an empty array: ```js export default defineConfig({ // ... presets: [] }) ``` This allows you to define your own tokens, without having to use the `extend` key in the theme. ```js export default defineConfig({ // ... theme: { tokens: { colors: { primary: { value: '#ff0000' } } } } }) ``` ## Removing default utilities Use the `eject: true` property to remove all the default utilities. Panda doesn't automatically know which tokens are valid for which CSS properties, so it is necessary to tell Panda that my tokens from the "colors" category are valid for the CSS property "color". ```js export default defineConfig({ // ... eject: true, utilities: { color: { values: 'colors' } }, theme: { tokens: { colors: { primary: { value: '#ff0000' } } } } }) ``` This makes `

Text

` work as expected. ## Re-using Panda presets Panda offers 2 presets: - `@pandacss/preset-base`: This is a relatively unopinionated set of utilities for mapping CSS properties to values (almost everyone will want these) You can use these presets by installing them via npm and adding them to your `presets` key: ```js export default defineConfig({ // ... presets: ['@pandacss/preset-base'] }) ``` - `@pandacss/preset-panda` as an opinionated set of tokens if you don't want to define your own colors/spacing/fonts etc. ```js export default defineConfig({ // ... presets: ['@pandacss/preset-panda'] }) ``` > Note: You don't need to install `@pandacss/preset-base` or `@pandacss/preset-panda`. Panda will automatically resolve > them for you. --- ## Multi-Theme Tokens Panda supports advance token definition beyond just light/dark mode; theming beyond just dark mode. You can define multi-theme tokens using nested conditions. ## Multi-Theme Tokens Panda supports advance token definition beyond just light/dark mode; theming beyond just dark mode. You can define multi-theme tokens using nested conditions. Let's say your application supports a pink and blue theme, and each theme can have a light and dark mode. Let's see how to model this in Panda. We'll start by defining the following conditions for these theme and color modes: ```js // panda.config.ts const config = { conditions: { light: '[data-color-mode=light] &', dark: '[data-color-mode=dark] &', pinkTheme: '[data-theme=pink] &', blueTheme: '[data-theme=blue] &' } } ``` > Conditions are a way to provide preset css selectors or media queries for use in your Panda project Next, we'll define a `colors.text` semantic token for the pink and blue theme. ```js // panda.config.ts const theme = { // ... semanticTokens: { colors: { text: { value: { _pinkTheme: '{colors.pink.500}', _blueTheme: '{colors.blue.500}' } } } } } ``` Next, we'll modify `colors.text` to support light and dark color modes for each theme. ```js // panda.config.ts const theme = { // ... semanticTokens: { colors: { text: { value: { _pinkTheme: { base: '{colors.pink.500}', _dark: '{colors.pink.300}' }, _blueTheme: { base: '{colors.blue.500}', _dark: '{colors.blue.300}' } } } } } } ``` Now, you can use the `text` token in your styles, and it will automatically change based on the theme and the color scheme. ```jsx // use pink and dark mode theme

Hello World

// use pink and light mode theme

Hello World

``` ## Multi-Themes The above example shows you how to define multi-theme tokens using nested conditions but you can also define clearly separated themes using the `themes` property in the config. This allows you to apply a `theme` on multiple tokens at once, using data attributes and CSS variables. > Theme variants can be applied using the `data-panda-theme` attribute with the theme key as the value. ```ts // panda.config.ts import { defineConfig } from '@pandacss/dev' export default defineConfig({ // ... // main theme theme: { extend: { tokens: { colors: { text: { value: 'green' } } }, semanticTokens: { colors: { body: { value: { base: '{colors.green.600}', _osDark: '{colors.green.400}' } } } } } }, // alternative theme variants themes: { primary: { tokens: { colors: { text: { value: 'red' } } }, semanticTokens: { colors: { muted: { value: '{colors.red.200}' }, body: { value: { base: '{colors.red.600}', _osDark: '{colors.red.400}' } } } } }, secondary: { tokens: { colors: { text: { value: 'blue' } } }, semanticTokens: { colors: { muted: { value: '{colors.blue.200}' }, body: { value: { base: '{colors.blue.600}', _osDark: '{colors.blue.400}' } } } } } } }) ``` ### Pregenerating themes By default, no additional theme variant is generated, you need to specify the specific themes you want to generate in `staticCss.themes` to include them in the CSS output. ```ts // panda.config.ts import { defineConfig } from '@pandacss/dev' export default defineConfig({ // ... staticCss: { themes: ['primary', 'secondary'] } }) ``` This will generate the following CSS: ```css @layer tokens { :where(:root, :host) { --colors-text: blue; --colors-body: var(--colors-blue-600); } [data-panda-theme='primary'] { --colors-text: red; --colors-muted: var(--colors-red-200); --colors-body: var(--colors-red-600); } @media (prefers-color-scheme: dark) { :where(:root, :host) { --colors-body: var(--colors-blue-400); } [data-panda-theme='primary'] { --colors-body: var(--colors-red-400); } } } ``` ### Dynamically importing themes An alternative way of applying a theme is by using the new `styled-system/themes` entrypoint where you can import the themes expected CSS and apply them in your app. > â„šī¸ The `styled-system/themes` will always contain every themes (tree-shaken if not used), whereas `staticCss.themes` only > applies to the CSS output. Each theme has a corresponding JSON file with a similar structure: ```json { "name": "primary", "id": "panda-themes-primary", "css": "[data-panda-theme=primary] { ... }" } ``` #### Dynamically import a theme using its name ```ts import { getTheme } from '../styled-system/themes' const theme = await getTheme('red') // ^? { // name: "red"; // id: string; // css: string; // } ``` #### Inject the theme styles into the DOM: ```ts import { injectTheme } from '../styled-system/themes' const theme = await getTheme('red') injectTheme(document.documentElement, theme) // this returns the injected style element ``` #### SSR example with NextJS: ```tsx // app/layout.tsx import { cookies } from 'next/headers' import './globals.css' import { ThemeName, getTheme } from '../../styled-system/themes' export default async function RootLayout({ children }: { children: React.ReactNode }) { const store = cookies() const themeName = store.get('theme')?.value as ThemeName const theme = themeName && (await getTheme(themeName)) return ( {themeName && (