Introduction
Panda CSS est un moteur de styling zero-runtime révolutionnaire pour React et Next.js, surpassant Tailwind par sa flexibilité et sa sécurité types. En 2026, avec l'essor des apps web performantes, Panda excelle grâce à ses recettes (composables et réutilisables), patterns (UI complexes) et extraction statique CSS. Contrairement aux solutions runtime coûteuses, Panda génère du CSS pur à la build-time, réduisant le JS bundle de 90%+.
Ce tutoriel advanced vous guide pas à pas pour un setup complet dans Next.js App Router : config TS avancée, variants conditionnels, états interactifs, responsive + dark mode, et patterns slot-based. Vous obtiendrez un projet fonctionnel, scalable et bookmarqué par tout dev senior. Prêt à transformer vos styles en code type-safe ? (128 mots)
Prérequis
- Node.js 20+ et npm/yarn/pnpm
- Next.js 15+ avec App Router et TypeScript
- Connaissances avancées en React hooks et Tailwind-like utilities
- Un éditeur comme VS Code avec extension Panda CSS (optionnel mais recommandé)
- Git pour versionner le projet
Installation du projet Next.js et Panda CSS
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/cssCe script crée un projet Next.js moderne sans Tailwind (supprimé ensuite), initialise Panda CSS et installe le runtime. L'init génère panda.config.ts et un preset de base. Lancez npm run dev après pour vérifier.
Configuration de base de Panda
La config se fait dans panda.config.ts. Elle définit les presets, utilities, thèmes et exclusions. Pour l'avancé, activez les recettes/patterns, le dark mode et les animations. Ajoutez des tokens custom pour cohérence design.
panda.config.ts complet avec thème et 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: [],
})Cette config avancée étend le thème avec tokens sémantiques, conditions CSS custom (hover, dark), une recette 'button' multi-variants et un pattern 'code' avec slots. Elle cible src/ pour l'extraction. Les _dark et _hover utilisent les conditions pour du CSS natif. Lancez npx panda cssgen pour générer le CSS.
Ajout du CSS Panda dans 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>
)
}Intégrez Panda dans le layout root avec css() pour appliquer thème light/dark. theme et darkTheme sont générés par Panda. suppressHydrationWarning évite les mismatches SSR. Cela active le color mode global.
Création de recettes avancées
Les recettes sont des objets composables avec variants, states (hover, focus) et compound variants. Imaginez-les comme des Lego : base + modificateurs. Pour advanced, combinez responsive, états et slots.
Recette Button avancée avec états et 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>
)
}Ce composant utilise styled de Panda et applique la recette button via button({ variants }). Types inférés auto via variantKeys. Ajoutez aria-* pour accessibilité. Totalement type-safe : VS Code auto-complete les props.
Pattern Card avec slots et 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>
)Le pattern code (renommé Card ici) utilise slots implicites via code.codeRoot. Ajout d'animations CSS natives (_hover, transition). styled('div') pour un slot custom. Slots permettent une composition granulaire sans prop drilling.
Intégration responsive et dark mode
Responsive : Utilisez sm:, md: etc. dans css() ou recettes. Dark mode : Préfixes _dark auto-générés. Testez avec localStorage.setItem('theme', 'dark').
Page d'exemple utilisant tous les composants
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>
)
}Cette page démontre grille responsive, boutons variants et Card pattern. css({ sm: {} }) applique media queries. Tout est server-rendered sans JS runtime. Lancez npx panda codegen puis npm run build pour optimiser.
Script de build et watch pour développement
{
"scripts": {
"dev": "next dev",
"build": "pnpm panda generate && next build",
"panda:watch": "pnpm panda --watch",
"panda:build": "pnpm panda generate",
"lint": "next lint"
}
}Ajoutez ces scripts à package.json. panda generate extrait et génère CSS/TS types. Utilisez concurrently pour watch en dev : concurrently "pnpm panda:watch" "next dev". Évite les rebuilds lents.
Bonnes pratiques
- Toujours utiliser recettes/patterns : Évite le css() inline pour la maintenance.
- Tokens sémantiques first :
bg: 'bg'au lieu de couleurs hardcodées pour thèmes. - Compound variants : Pour des combos comme
size=lg + variant=outline. - Plugins custom : Étendez Panda avec
plugins: [monPlugin()]pour animations avancées. - Génération CI/CD : Intégrez
panda generatedans build pipeline.
Erreurs courantes à éviter
- Oublier
panda generate: Pas de styles sans génération post-install. - Mix Tailwind/Panda : Conflits PostCSS ; supprimez Tailwind.
- Props non typées : Utilisez
recipeKeyspour inférence auto. - États sans transitions : Ajoutez toujours
transition: 'all 0.15s'pour UX fluide.
Pour aller plus loin
Plongez dans les docs officielles Panda CSS pour plugins avancés. Maîtrisez les animations avec @keyframes custom. Découvrez nos formations Learni sur React/Next.js avancés pour scaler vos skills frontend.