Panda CSS is the CSS-in-JS engine with build-time static extraction — you get the DX of styled-components with the performance of Tailwind. And it's completely free.
Why Panda CSS?
The CSS-in-JS ecosystem has a problem: runtime overhead. styled-components and Emotion inject styles at runtime, which hurts performance. Tailwind solves this but loses type safety and colocation.
Panda CSS gives you both: write styles in TypeScript, extract them at build time to atomic CSS. Zero runtime.
Quick Start
# Install
npm install -D @pandacss/dev
# Initialize
npx panda init --postcss
# Generate utilities
npx panda codegen
// panda.config.ts
import { defineConfig } from "@pandacss/dev";
export default defineConfig({
preflight: true,
include: ["./src/**/*.{js,jsx,ts,tsx}"],
theme: { extend: {} },
outdir: "styled-system",
});
Type-Safe Styling (The Killer Feature)
import { css } from "../styled-system/css";
function Button() {
return (
<button className={css({
bg: "blue.500", // ✅ autocomplete
color: "white", // ✅ type-checked
px: "4",
py: "2",
rounded: "lg",
_hover: { // ✅ conditions are typed
bg: "blue.600"
},
_focus: {
ring: "2",
ringColor: "blue.300"
}
})}>
Click me
</button>
);
}
Every token is autocompleted. Typos are caught at build time. No more bg-bleu-500 bugs.
Recipes (Component Variants)
import { cva } from "../styled-system/css";
const button = cva({
base: {
display: "inline-flex",
alignItems: "center",
fontWeight: "semibold",
rounded: "lg",
cursor: "pointer",
},
variants: {
visual: {
solid: { bg: "blue.500", color: "white" },
outline: { border: "2px solid", borderColor: "blue.500", color: "blue.500" },
ghost: { color: "blue.500", _hover: { bg: "blue.50" } },
},
size: {
sm: { px: "3", py: "1.5", fontSize: "sm" },
md: { px: "4", py: "2", fontSize: "md" },
lg: { px: "6", py: "3", fontSize: "lg" },
},
},
defaultVariants: {
visual: "solid",
size: "md",
},
});
// Usage — fully typed!
<button className={button({ visual: "outline", size: "lg" })}>
Subscribe
</button>
Patterns (Layout Primitives)
import { stack, hstack, grid, center } from "../styled-system/patterns";
function Layout() {
return (
<div className={stack({ gap: "4", p: "6" })}>
<nav className={hstack({ justify: "space-between" })}>
<h1>Logo</h1>
<div className={hstack({ gap: "2" })}>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</div>
</nav>
<main className={grid({ columns: 3, gap: "6" })}>
<div className={center({ h: "200px", bg: "gray.100", rounded: "xl" })}>
Card 1
</div>
<div className={center({ h: "200px", bg: "gray.100", rounded: "xl" })}>
Card 2
</div>
</main>
</div>
);
}
Token System
// panda.config.ts
export default defineConfig({
theme: {
tokens: {
colors: {
brand: {
50: { value: "#eff6ff" },
500: { value: "#3b82f6" },
900: { value: "#1e3a5f" },
},
},
fonts: {
body: { value: "Inter, sans-serif" },
mono: { value: "Fira Code, monospace" },
},
},
semanticTokens: {
colors: {
text: {
value: { base: "{colors.brand.900}", _dark: "{colors.brand.50}" },
},
},
},
},
});
Semantic tokens automatically switch between light/dark mode.
Panda vs Tailwind vs styled-components
| Feature | Panda CSS | Tailwind CSS | styled-components |
|---|---|---|---|
| Type safety | Full TypeScript | None | Partial |
| Runtime cost | Zero | Zero | Yes (JS bundle) |
| Autocomplete | Full | With plugin | Partial |
| Variants | Built-in CVA | Custom | Props |
| Dark mode | Semantic tokens | Class strategy | ThemeProvider |
| Colocation | With component | In className | With component |
Need to scrape data from any website and get it in structured JSON? Check out my web scraping tools on Apify — no coding required, results in minutes.
Have a custom data extraction project? Email me at spinov001@gmail.com — I build tailored scraping solutions for businesses.
Top comments (0)