Panda CSS
"Panda CSS: build-time CSS-in-JS, atomic CSS, recipes, patterns, tokens, conditions, RSC compatible, type-safe styles"
Panda CSS is a build-time CSS-in-JS engine that generates atomic CSS from TypeScript style definitions. It combines the developer experience of CSS-in-JS (co-located styles, type safety, design tokens) with the performance of static CSS extraction. Every style call is analyzed at build time and compiled into small, reusable atomic class names, producing highly cacheable and deduplicated stylesheets. Panda is fully compatible with React Server Components because no JavaScript is shipped to the client for styling. It provides a layered API: raw `css()` for ad-hoc styles, `recipes` for component variants, `patterns` for layout primitives, and a token system for design consistency.
## Key Points
1. **Use semantic tokens for colors.** Define `surface`, `text.primary`, `border.subtle` as semantic tokens that resolve differently in light and dark mode rather than using raw color scales.
2. **Run `panda codegen` in CI.** Include codegen as a build step and commit the `styled-system/` output so type checking works in editors and CI pipelines.
3. **Use patterns for layout, css() for visual styling.** Patterns like `stack`, `flex`, and `grid` handle spacing and layout. Use `css()` for colors, borders, and visual details.
4. **Prefer recipes for reusable components.** Recipes provide a clean variant API, enable compound variants, and keep style logic centralized.
5. **Leverage responsive arrays/objects consistently.** Use `{ base: "4", md: "6", lg: "8" }` for responsive values rather than manually writing media queries.
6. **Keep token scales small and intentional.** Avoid creating dozens of one-off token values; curate a tight scale for spacing, font sizes, and colors.
2. **Importing from `styled-system/` in server-only modules without codegen.** If codegen has not run, the imports will be missing and the build will fail.
3. **Mixing Panda with another CSS-in-JS library.** Running Emotion or styled-components alongside Panda introduces a second runtime and conflicting class-name strategies.
4. **Over-nesting conditional styles.** Deeply nested `_hover: { _dark: { _first: { ... } } }` becomes unreadable. Extract shared conditions into recipe variants instead.
5. **Ignoring the `include` configuration.** If source files are not in the `include` glob, Panda will not scan them and the generated CSS will be incomplete, causing invisible styling failures.
## Quick Example
```bash
npm install -D @pandacss/dev
npx panda init --postcss
```
```css
/* app/globals.css */
@layer reset, base, tokens, recipes, utilities;
```skilldb get css-styling-services-skills/Panda CSSFull skill: 382 linesPanda CSS
Core Philosophy
Panda CSS is a build-time CSS-in-JS engine that generates atomic CSS from TypeScript style definitions. It combines the developer experience of CSS-in-JS (co-located styles, type safety, design tokens) with the performance of static CSS extraction. Every style call is analyzed at build time and compiled into small, reusable atomic class names, producing highly cacheable and deduplicated stylesheets. Panda is fully compatible with React Server Components because no JavaScript is shipped to the client for styling. It provides a layered API: raw css() for ad-hoc styles, recipes for component variants, patterns for layout primitives, and a token system for design consistency.
Setup
Installation
npm install -D @pandacss/dev
npx panda init --postcss
Panda Configuration
// panda.config.ts
import { defineConfig } from "@pandacss/dev";
export default defineConfig({
preflight: true,
include: [
"./src/**/*.{ts,tsx}",
"./app/**/*.{ts,tsx}",
],
exclude: [],
theme: {
extend: {
tokens: {
colors: {
brand: {
50: { value: "#eff6ff" },
500: { value: "#3b82f6" },
600: { value: "#2563eb" },
700: { value: "#1d4ed8" },
900: { value: "#1e3a8a" },
},
},
fonts: {
body: { value: "'Inter', sans-serif" },
heading: { value: "'Cal Sans', 'Inter', sans-serif" },
},
},
semanticTokens: {
colors: {
surface: {
value: { base: "{colors.white}", _dark: "{colors.gray.900}" },
},
text: {
primary: {
value: { base: "{colors.gray.900}", _dark: "{colors.gray.50}" },
},
secondary: {
value: { base: "{colors.gray.600}", _dark: "{colors.gray.400}" },
},
},
border: {
subtle: {
value: { base: "{colors.gray.200}", _dark: "{colors.gray.700}" },
},
},
},
},
},
},
jsxFramework: "react",
outdir: "styled-system",
});
PostCSS Integration
// postcss.config.cjs
module.exports = {
plugins: {
"@pandacss/dev/postcss": {},
},
};
CSS Entry Point
/* app/globals.css */
@layer reset, base, tokens, recipes, utilities;
Code Generation
npx panda codegen
Key Techniques
Using the css() Function
import { css } from "../../styled-system/css";
function ProfileHeader({ user }: { user: User }) {
return (
<header
className={css({
display: "flex",
alignItems: "center",
gap: "4",
p: "6",
bg: "surface",
borderRadius: "xl",
borderWidth: "1px",
borderColor: "border.subtle",
shadow: "sm",
_hover: { shadow: "md" },
transition: "shadows",
})}
>
<img
src={user.avatar}
alt={user.name}
className={css({
w: "16",
h: "16",
rounded: "full",
objectFit: "cover",
})}
/>
<div>
<h1
className={css({
fontSize: "2xl",
fontWeight: "bold",
color: "text.primary",
fontFamily: "heading",
})}
>
{user.name}
</h1>
<p className={css({ fontSize: "sm", color: "text.secondary", mt: "1" })}>
{user.role}
</p>
</div>
</header>
);
}
Recipes for Component Variants
// button.recipe.ts
import { cva, type RecipeVariantProps } from "../../styled-system/css";
export const buttonStyle = cva({
base: {
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
fontWeight: "medium",
rounded: "lg",
cursor: "pointer",
transition: "colors",
_focusVisible: {
outline: "2px solid",
outlineColor: "brand.500",
outlineOffset: "2px",
},
_disabled: {
opacity: 0.5,
cursor: "not-allowed",
},
},
variants: {
intent: {
primary: {
bg: "brand.500",
color: "white",
_hover: { bg: "brand.600" },
_active: { bg: "brand.700" },
},
secondary: {
bg: "transparent",
color: "text.primary",
borderWidth: "1px",
borderColor: "border.subtle",
_hover: { bg: "gray.50", _dark: { bg: "gray.800" } },
},
danger: {
bg: "red.500",
color: "white",
_hover: { bg: "red.600" },
},
},
size: {
sm: { fontSize: "sm", px: "3", py: "1.5", gap: "1.5" },
md: { fontSize: "md", px: "4", py: "2", gap: "2" },
lg: { fontSize: "lg", px: "6", py: "3", gap: "2.5" },
},
},
defaultVariants: {
intent: "primary",
size: "md",
},
});
export type ButtonVariants = RecipeVariantProps<typeof buttonStyle>;
Using Recipes in Components
import { buttonStyle, type ButtonVariants } from "./button.recipe";
type ButtonProps = ButtonVariants &
React.ButtonHTMLAttributes<HTMLButtonElement> & {
leftIcon?: React.ReactNode;
};
export function Button({ intent, size, leftIcon, children, ...props }: ButtonProps) {
return (
<button className={buttonStyle({ intent, size })} {...props}>
{leftIcon && <span>{leftIcon}</span>}
{children}
</button>
);
}
Patterns for Layout Primitives
import { flex, grid, stack, center } from "../../styled-system/patterns";
function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div className={flex({ direction: "column", minH: "dvh" })}>
<nav className={center({ h: "16", px: "6", borderBottomWidth: "1px" })}>
<span>Dashboard</span>
</nav>
<main className={flex({ flex: "1", overflow: "hidden" })}>
<aside
className={stack({
gap: "2",
w: "64",
p: "4",
borderRightWidth: "1px",
hideBelow: "md",
})}
>
{/* Sidebar nav items */}
</aside>
<section className={grid({
columns: { base: 1, md: 2, lg: 3 },
gap: "6",
p: "6",
flex: "1",
overflow: "auto",
})}>
{children}
</section>
</main>
</div>
);
}
Responsive and Conditional Styles
import { css } from "../../styled-system/css";
function FeatureCard({ feature }: { feature: Feature }) {
return (
<article
className={css({
p: { base: "4", md: "6" },
rounded: "xl",
bg: "surface",
borderWidth: "1px",
borderColor: "border.subtle",
display: "flex",
flexDir: { base: "column", md: "row" },
gap: { base: "3", md: "6" },
_hover: { borderColor: "brand.500" },
_dark: { bg: "gray.800" },
})}
>
<div
className={css({
w: { base: "full", md: "48" },
h: { base: "40", md: "auto" },
rounded: "lg",
overflow: "hidden",
flexShrink: 0,
})}
>
<img
src={feature.image}
alt=""
className={css({ w: "full", h: "full", objectFit: "cover" })}
/>
</div>
<div className={css({ flex: "1" })}>
<h3 className={css({ fontSize: "xl", fontWeight: "semibold", color: "text.primary" })}>
{feature.title}
</h3>
<p className={css({ mt: "2", color: "text.secondary", lineHeight: "relaxed" })}>
{feature.description}
</p>
</div>
</article>
);
}
Slot Recipes for Multi-Part Components
// card.slot-recipe.ts
import { sva } from "../../styled-system/css";
export const card = sva({
slots: ["root", "header", "body", "footer"],
base: {
root: {
bg: "surface",
rounded: "xl",
borderWidth: "1px",
borderColor: "border.subtle",
overflow: "hidden",
},
header: {
px: "6",
py: "4",
borderBottomWidth: "1px",
borderColor: "border.subtle",
fontWeight: "semibold",
},
body: { px: "6", py: "4" },
footer: {
px: "6",
py: "4",
borderTopWidth: "1px",
borderColor: "border.subtle",
display: "flex",
justifyContent: "flex-end",
gap: "3",
},
},
variants: {
elevated: {
true: { root: { shadow: "lg", borderWidth: "0" } },
},
},
});
Best Practices
- Use semantic tokens for colors. Define
surface,text.primary,border.subtleas semantic tokens that resolve differently in light and dark mode rather than using raw color scales. - Run
panda codegenin CI. Include codegen as a build step and commit thestyled-system/output so type checking works in editors and CI pipelines. - Use patterns for layout, css() for visual styling. Patterns like
stack,flex, andgridhandle spacing and layout. Usecss()for colors, borders, and visual details. - Prefer recipes for reusable components. Recipes provide a clean variant API, enable compound variants, and keep style logic centralized.
- Leverage responsive arrays/objects consistently. Use
{ base: "4", md: "6", lg: "8" }for responsive values rather than manually writing media queries. - Keep token scales small and intentional. Avoid creating dozens of one-off token values; curate a tight scale for spacing, font sizes, and colors.
Anti-Patterns
- Using runtime style calculations in css(). Panda extracts styles at build time. Dynamic expressions like
css({ width: \${percent}%` })will not work; use inlinestyle` for truly dynamic values. - Importing from
styled-system/in server-only modules without codegen. If codegen has not run, the imports will be missing and the build will fail. - Mixing Panda with another CSS-in-JS library. Running Emotion or styled-components alongside Panda introduces a second runtime and conflicting class-name strategies.
- Over-nesting conditional styles. Deeply nested
_hover: { _dark: { _first: { ... } } }becomes unreadable. Extract shared conditions into recipe variants instead. - Ignoring the
includeconfiguration. If source files are not in theincludeglob, Panda will not scan them and the generated CSS will be incomplete, causing invisible styling failures.
Install this skill directly: skilldb add css-styling-services-skills
Related Skills
CSS Modules
"CSS Modules: scoped CSS, composition, global styles, Next.js integration, TypeScript declarations, naming conventions"
Lightning CSS
"Lightning CSS: ultra-fast CSS transformer, bundler, and minifier written in Rust, with modern syntax lowering, vendor prefixing, and CSS modules"
Stitches
"Stitches: near-zero runtime CSS-in-JS, variants API, theme tokens, responsive styles, SSR support, polymorphic components"
Styled Components
"styled-components: CSS-in-JS, tagged template literals, theming, dynamic styles, SSR, global styles, extending"
Tailwind CSS
"Tailwind CSS: utility-first CSS, responsive design, dark mode, custom theme, plugins, @apply, JIT, content configuration, arbitrary values"
UnoCSS
"UnoCSS: instant on-demand atomic CSS engine, presets, shortcuts, rules, variants, attributify mode, icon support, inspector"