
Panda CSS를 1.10 버전을 기반으로 정리한 내용
해당 글은 Panda CSS 1.10 버전을 기반으로 정리한 내용입니다.
Panda CSS는 빌드 타임에 동작하는 Zero-runtime CSS-in-JS 라이브러리이다.
기존 Styled-components나 Emotion이 브라우저 런타임에 스타일을 계산하여 성능 저하를 일으킬 수 있는 반면, Panda CSS는 빌드 단계에서 정적인 CSS 파일을 생성한다. 또한 완벽한 타입 추론을 제공하여 오타로 인한 스타일 에러를 사전에 방지할 수 있다.
npm install -D @pandacss/dev postcss
npm panda init -p이 명령어를 실행하면 panda.config.ts 파일과 postcss.config.cjs 파일이 생성되며, 스타일 유틸리티가 포함된 styled-system 폴더가 만들어진다.
panda.config.ts 구성Panda 엔진이 스캔할 파일 경로를 지정한다.
import { defineConfig } from "@pandacss/dev"
export default defineConfig({
// CSS Reset을 사용할지 여부
preflight: true,
// Panda가 스타일을 찾을 파일 확장자 및 경로
include: ["./src/**/*.{js,jsx,ts,tsx}", "./app/**/*.{js,jsx,ts,tsx}"],
// 제외할 경로
exclude: [],
// 커스텀 테마 (디자인 토큰)
theme: {
extend: {}
},
// 결과물이 생성될 폴더 이름
outdir: "styled-system",
})@layer reset, base, tokens, recipes, utilities;Pands CSS는 styled-system 폴더에서 함수를 불러와서 사용한다.
css 함수import { css } from '../styled-system/css'
function Button() {
return (
<button className={css({
bg: 'blue.500',
color: 'white',
px: '4',
py: '3',
borderRadius: 'md',
_hover: { bg: 'blue.600' }
})}>
클릭하세요
</button>
)
}import { flex, grid } from '../styled-system/patterns'
function Layout() {
return (
<div className={flex({ direction: 'column', align: 'center', gap: '4' })}>
<div className={grid({ columns: 2, gap: '2' })}>
<div>아이템 1</div>
<div>아이템 2</div>
</div>
</div>
)
}panda.config.ts 에서 정의한 색상, 폰트 사이즈 등을 코드에서 참조theme: {
extend: {
tokens: {
colors: {
primary: { value: '#0F52BA' }
}
}
}
}
// 컴포넌트에서의 사용
const className = css({ color: 'primary' })Recipe의 cva 함수를 통해 다양한 상태를 가진 컴포넌트를 정의할 수 있다.
cva는 단일 요소의 Recipe를 정의하는 데 좋다.
defineRecipe 을 통해 panda.config.ts 에 전역 Recipe을 등록하고 컴포넌트에서 이를 활용할 수 있다.
base: 컴포넌트의 기본 스타일variants : 컴포넌트의 상태 별 스타일 정의compoundVariants : 복합 변형 스타일 정의defaultVariants : 기본 상태// button.recipe.ts
import { defineRecipe } from '@pandacss/dev'
export const buttonRecipe = defineRecipe({
className: 'button',
description: 'The styles for the Button component',
base: {
display: 'flex'
},
variants: {
visual: {
funky: { bg: 'red.200', color: 'white' },
edgy: { border: '1px solid {colors.red.500}' }
},
size: {
sm: { padding: '4', fontSize: '12px' },
lg: { padding: '8', fontSize: '40px' }
},
shape: {
square: { borderRadius: '0' },
circle: { borderRadius: 'full' }
}
// panda.config.ts
import { defineConfig } from '@pandacss/dev'
import { buttonRecipe } from './button.recipe'
export default defineConfig({
//...
jsxFramework: 'react',
theme: {
extend: {
recipes: {
button: buttonRecipe
}
}
}
})// recipe 사용
import { button } from '../styled-system/recipes'
function App() {
return (
<div>
<button className={button()}>Click me</button>
<button className={button({ shape: 'circle' })}>Click me</button>
</div>
)
}cva 가 단일 요소를 위한 기능이었다면, sva 는 여러 요소로 구성된 복합 컴포넌트를 위한 기능이다. 여러 개의 하위 요소들의 스타일과 상태를 한 곳에서 관리할 수 있게 해준다.
만약 Card 컴포넌트를 만든다고 가정할 때, Card 컴포넌트는 보통컨테이너 , 헤더 , 본문 , 푸터 로 구성되어 있다.
lg 로 변할 때마다 컨테이너 패딩, 헤더 폰트 크기, 본문 여백 등을 각각의 하위 요소 Recipe에서 따로 제어해야 한다. 즉, 상태 동기화가 매우 까다롭다.size: 'lg' 라는 상태 하나만 주입하면, 정의해둔 root , header , body 의 스타일이 일제히 사이즈에 맞게 변형된다.// checkbox.recipe.ts
import { sva } from '../styled-system/css'
const cardRecipe = sva({
// 1. 컴포넌트를 구성하는 슬롯(하위 요소)들을 정의합니다.
slots: ['root', 'header', 'body', 'footer'],
// 2. 각 슬롯의 기본 스타일을 정의합니다.
base: {
root: { display: 'flex', flexDirection: 'column', borderWidth: '1px', borderRadius: 'md' },
header: { padding: '4', borderBottomWidth: '1px', fontWeight: 'bold' },
body: { padding: '4', flex: '1' },
footer: { padding: '4', bg: 'gray.50' }
},
// 3. 상태(Variant)에 따라 슬롯들의 스타일이 어떻게 변할지 정의합니다.
variants: {
size: {
sm: {
root: { fontSize:
// Card.tsx
import { cardRecipe } from '../styled-system/recipes'
import type { ComponentProps } from 'react'
// 레시피의 Variant 타입을 추출합니다. (예: { size?: 'sm' | 'lg', visual?: 'elevated' | 'outline' })
type CardVariants = Parameters<typeof cardRecipe>[0]
interface CardProps extends CardVariants {
title: string
content: string
footerText?: string
}
export const Card = ({ title, content, footerText, size, visual }: CardProps) => {
// 1. 선택된 variant를 넣어 sva 함수를 실행합니다.
const classes = cardRecipe
// Card 사용: 크기는 크고, 그림자가 있는 카드 생성 (내부의 header, body 패딩이 모두 자동으로 lg 사이즈에 맞춰짐)
<Card
size="lg"
visual="elevated"
title="공지사항"
content="Panda CSS Slot Recipe 업데이트 안내"
/>