Introduction
Panda CSS is a revolutionary zero-runtime styling engine for React and Next.js that outperforms Tailwind with its flexibility and type safety. In 2026, as high-performance web apps rise, Panda shines with recipes (composable and reusable), patterns (complex UI), and static CSS extraction. Unlike costly runtime solutions, Panda generates pure CSS at build time, slashing JS bundles by 90%+.
This advanced tutorial guides you step-by-step through a complete Next.js App Router setup: advanced TS config, conditional variants, interactive states, responsive + dark mode, and slot-based patterns. You'll end up with a functional, scalable project bookmarked by every senior dev. Ready to turn your styles into type-safe code?
Prerequisites
- Node.js 20+ and npm/yarn/pnpm
- Next.js 15+ with App Router and TypeScript
- Advanced knowledge of React hooks and Tailwind-like utilities
- An editor like VS Code with the Panda CSS extension (optional but recommended)
- Git for versioning the project
Next.js Project and Panda CSS Installation
npx create-next-app@latest mon-projet-panda --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"
cd mon-projet-panda
npm uninstall tailwindcss postcss autoprefixer
npx @pandacss/dev@latest init
npm install @pandacss/cssThis script creates a modern Next.js project without Tailwind (removed afterward), initializes Panda CSS, and installs the runtime. The init generates panda.config.ts and a base preset. Run npm run dev afterward to verify.
Basic Panda Configuration
Configuration happens in panda.config.ts. It defines presets, utilities, themes, and exclusions. For advanced use, enable recipes/patterns, dark mode, and animations. Add custom tokens for design consistency.
Complete panda.config.ts with Theme and Presets
import { defineConfig } from '@pandacss/dev'
export default defineConfig({
preflight: true,
theme: {
extend: {
tokens: {
colors: {
primary: { value: '{colors.blue.500}' },
neutral: {
50: { value: '#f8fafc' },
900: { value: '#0f172a' }
}
},
spacing: {
xs: { value: '0.5rem' },
xl: { value: '3rem' }
}
},
breakpoints: {
xs: '30em',
xl: '80em'
}
},
semanticTokens: {
colors: {
bg: { value: '{colors.neutral.50}' },
bgDark: { value: '{colors.neutral.900}' }
}
}
},
globalCss: {
body: {
bg: '{colors.bg}',
color: '{colors.neutral.900}',
_dark: { bg: '{colors.bgDark}' }
}
},
conditions: {
sm: '@media (min-width: 640px)',
dark: '@media (prefers-color-scheme: dark)',
hover: '&:hover',
focus: '&:focus-visible'
},
patterns: {
code: {
description: 'Code block',
properties: [{ name: 'variant', type: 'enum', default: 'default', values: ['default', 'ghost'] }],
slots: ['container', 'badge'],
style: {
container: {
base: { p: '2', bg: 'neutral.100', rounded: 'md', _dark: { bg: 'neutral.800' } },
variants: {
variant: {
ghost: { bg: 'transparent' }
}
}
},
badge: {
base: { px: '1.5', py: '0.5', fontSize: 'sm', fontWeight: 'bold', bg: 'accent', color: 'white', rounded: 'full' }
}
}
}
},
recipes: {
button: {
description: 'A customizable button',
className: 'btn',
jsx: ['Button', 'button'],
variants: {
size: {
sm: { fontSize: 'sm', px: 'xs', py: '1.5', height: '2rem' },
lg: { fontSize: 'lg', px: 'xl', py: '2', height: '3rem' }
},
variant: {
solid: { bg: 'primary', color: 'white', _hover: { bg: '{colors.primary.600}' } },
outline: { border: '2px solid currentColor', _hover: { bg: 'primary.50' } },
ghost: { _hover: { bg: 'neutral.100' } }
}
},
defaultVariants: {
size: 'sm',
variant: 'solid'
}
}
},
src: ['./src/**/*.{ts,tsx}'],
outdir: 'styled-system',
include: ['./src/**/*.{js,jsx,ts,tsx}'],
exclude: [],
})This advanced config extends the theme with semantic tokens, custom CSS conditions (hover, dark), a multi-variant 'button' recipe, and a 'code' pattern with slots. It targets the src/ folder for extraction. _dark and _hover leverage conditions for native CSS. Run npx panda cssgen to generate the CSS.
Adding Panda CSS to layout.tsx
import type { Metadata } from 'next'
import { css } from '../styled-system/css'
import { darkTheme, theme } from '../styled-system/theme'
import './globals.css'
export const metadata: Metadata = {
title: 'Panda CSS Advanced',
description: 'Tutoriel Panda CSS avancé',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="fr" suppressHydrationWarning>
<body>
<div className={css(
{
theme,
darkTheme,
colorMode: { base: 'light', _dark: 'dark' },
},
'min-h-screen w-full'
)}>
{children}
</div>
</body>
</html>
)
}Integrate Panda into the root layout with css() to apply light/dark themes. theme and darkTheme are generated by Panda. suppressHydrationWarning prevents SSR mismatches. This enables global color mode.
Creating Advanced Recipes
Recipes are composable objects with variants, states (hover, focus), and compound variants. Think of them as Lego bricks: base + modifiers. For advanced use, combine responsive, states, and slots.
Advanced Button Recipe with States and Responsive
import { styled } from '../styled-system/jsx'
import { button } from '../styled-system/recipes'
const ButtonVariant = button.variantKeys
const ButtonSize = button.sizeKeys
type ButtonProps = {
variant?: ButtonVariant
size?: ButtonSize
children: React.ReactNode
className?: string
}
export const Button = ({
variant,
size,
children,
className,
}: ButtonProps) => {
return (
<styled.button
className={button({ size, variant, className })}
role="button"
>
{children}
</styled.button>
)
}This component uses Panda's styled and applies the button recipe via button({ variants }). Types inferred automatically via variantKeys. Add aria-* for accessibility. Fully type-safe with VS Code autocomplete for props.
Card Pattern with Slots and Conditions
import { styled } from '../styled-system/jsx'
import { code } from '../styled-system/patterns'
type CardProps = {
children: React.ReactNode
variant?: 'default' | 'ghost'
className?: string
}
export const CardContainer = styled('div', {
base: {
p: '6',
bg: 'bg',
rounded: 'lg',
shadow: 'md',
_dark: { bg: 'bgDark' },
_hover: { shadow: 'lg', transform: 'translateY(-2px)' },
transition: 'all 0.2s ease'
}
})
export const Card = ({ children, variant = 'default', className }: CardProps) => (
<code.codeRoot className={code({ variant, className })}>
{children}
</code.codeRoot>
)The code pattern (renamed Card here) uses implicit slots via code.codeRoot. Adds native CSS animations (_hover, transition). styled('div') for custom slots. Slots enable granular composition without prop drilling.
Responsive and Dark Mode Integration
Responsive: Use sm:, md: etc. in css() or recipes. Dark mode: Auto-generated _dark prefixes. Test with localStorage.setItem('theme', 'dark').
Example Page Using All Components
import { css } from '../styled-system/css'
import { Button } from '@/components/ui/Button'
import { Card } from '@/components/ui/Card'
export default function Home() {
return (
<main className={css({ p: '10', maxW: '4xl', mx: 'auto' })}>
<h1 className={css({ textStyle: '2xl', fontWeight: 'bold', mb: '8', textAlign: 'center' })}>
Panda CSS Avancé en Action
</h1>
<div className={css({ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: '6' })}>
<Card>
<h2 className={css({ fontSize: 'xl', fontWeight: 'semibold', mb: '4' })}>
Bouton Solid Responsive
</h2>
<Button size="lg" variant="solid" className={css({ w: 'full', sm: { w: 'auto' } })}>
Cliquez-moi
</Button>
</Card>
<Card variant="ghost">
<h2 className={css({ fontSize: 'xl', mb: '4' })}>
Bouton Ghost Dark Mode
</h2>
<Button size="sm" variant="ghost">
Ghost Button
</Button>
</Card>
</div>
</main>
)
}This page showcases responsive grid, variant buttons, and Card pattern. css({ sm: {} }) applies media queries. Everything server-renders without JS runtime. Run npx panda codegen then npm run build to optimize.
Build and Watch Scripts for Development
{
"scripts": {
"dev": "next dev",
"build": "pnpm panda generate && next build",
"panda:watch": "pnpm panda --watch",
"panda:build": "pnpm panda generate",
"lint": "next lint"
}
}Add these scripts to package.json. panda generate extracts and generates CSS/TS types. Use concurrently for dev watch: concurrently "pnpm panda:watch" "next dev". Avoids slow rebuilds.
Best Practices
- Always use recipes/patterns: Avoids inline css() for better maintenance.
- Semantic tokens first: Use
bg: 'bg'instead of hardcoded colors for themes. - Compound variants: For combos like
size=lg + variant=outline. - Custom plugins: Extend Panda with
plugins: [myPlugin()]for advanced animations. - CI/CD generation: Integrate
panda generateinto your build pipeline.
Common Errors to Avoid
- Forgetting
panda generate: No styles without post-install generation. - Mixing Tailwind/Panda: PostCSS conflicts; remove Tailwind.
- Untyped props: Use
recipeKeysfor auto-inference. - States without transitions: Always add
transition: 'all 0.15s'for smooth UX.
Next Steps
Dive into the official Panda CSS docs for advanced plugins. Master animations with custom @keyframes. Check out our Learni courses on advanced React/Next.js to level up your frontend skills.