Chakra UI 마이그레이션: v2 → v3
당신은 개발자가 Chakra UI v2에서 v3로 프로젝트를 마이그레이션하도록 안내하고 있습니다. 아래 단계를 순서대로 진행하세요. 먼저 프로젝트를 검사하고, 패키지 버전이나 프레임워크를 추측하지 마세요.
Node 요구사항: Chakra UI v3는 Node >= 20.x가 필요합니다. 환경이 확실하지 않은 경우 진행하기 전에 확인하세요.
1단계 — 프로젝트 검사
다음 파일을 읽어 현재 상태를 파악하세요:
package.json
다음을 찾으세요:
- 현재
@chakra-ui/react버전 (v2.x vs v3.x) - 관련 패키지:
@chakra-ui/icons,@chakra-ui/hooks,@chakra-ui/next-js,@emotion/styled,framer-motion - 프레임워크: Next.js (App Router 또는 Pages Router), Vite, 일반 React
- 패키지 매니저 (lockfiles에서 확인:
pnpm-lock.yaml,yarn.lock,bun.lock,package-lock.json)
또한 필요할 때 주요 파일을 빠르게 확인하세요:
- Provider / 테마 설정 (
_app.tsx,layout.tsx,theme.ts) - 컬러 모드 사용 (
ColorModeScript,useColorMode,useColorModeValue) - v2 패턴이 많이 사용된 컴포넌트 파일
2단계 — 패키지 업데이트
v2 전용 의존성 제거
# npm
npm uninstall @chakra-ui/icons @chakra-ui/hooks @chakra-ui/next-js @emotion/styled framer-motion
# pnpm
pnpm remove @chakra-ui/icons @chakra-ui/hooks @chakra-ui/next-js @emotion/styled framer-motion
# yarn
yarn remove @chakra-ui/icons @chakra-ui/hooks @chakra-ui/next-js @emotion/styled framer-motion
@emotion/styled와 framer-motion은 v3에서 더 이상 필요하지 않습니다.
v3 핵심 패키지 설치
# npm
npm install @chakra-ui/react @emotion/react
# pnpm
pnpm add @chakra-ui/react @emotion/react
# yarn
yarn add @chakra-ui/react @emotion/react
제거된 패키지의 대체품
| 제거됨 | 대체품 |
|---|---|
@chakra-ui/icons | lucide-react 또는 react-icons |
@chakra-ui/hooks | react-use 또는 usehooks-ts |
@chakra-ui/next-js | asChild prop 패턴 (Next.js 섹션 참고) |
3단계 — codemod 실행
공식 codemod는 대부분의 기계적인 변경(컴포넌트 이름 변경, prop 업데이트, import 재작성, 복합 컴포넌트 구조 변경)을 처리합니다. 수동 검토를 대체하지는 않으므로 출력 결과를 감사할 계획을 세우세요.
먼저 dry run 실행 (파일 변경 없음):
npx @chakra-ui/codemod upgrade --dry
제안 사항을 검토하세요. 만족스러우면:
npx @chakra-ui/codemod upgrade
codemod 후, 수동 편집을 하기 전에 변경 사항을 커밋하여 깨끗한 diff를 확보하세요.
4단계 — Provider 업데이트
이전 v2 패턴
// v2
import { ChakraProvider } from "@chakra-ui/react"
import theme from "./theme"
;<ChakraProvider theme={theme}>{children}</ChakraProvider>
새 v3 패턴 (Chakra CLI 스니펫 사용)
Provider 및 컴포넌트 스니펫을 생성합니다:
npx @chakra-ui/cli snippet add
이 명령은 components/ui/provider.tsx (그리고 toaster와 tooltip 스니펫)를 생성하고 필요한 npm 의존성( next-themes 포함)을 자동으로 설치합니다. 이를 import하여 사용하세요:
// v3 — app/layout.tsx (Next.js App Router)
import { Provider } from "@/components/ui/provider"
;<html lang="en" suppressHydrationWarning>
<body>
<Provider>{children}</Provider>
</body>
</html>
Provider 파일에는 "use client"가 포함되어 있습니다 — layout.tsx에 추가하지 마세요. Pages Router 배치에 대해서는 Next.js 섹션을 참고하세요.
v3에서 사용자 정의 테마
extendTheme을 createSystem으로 대체:
// v2
import { extendTheme } from "@chakra-ui/react"
// v3
import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react"
export const theme = extendTheme({ colors: { brand: { 500: "#2196f3" } } })
const config = defineConfig({
theme: { tokens: { colors: { brand: { 500: { value: "#2196f3" } } } } },
})
export const system = createSystem(defaultConfig, config)
value={system}을 통해 ChakraProvider에 system을 전달하세요.
5단계 — 컬러 모드 마이그레이션
모든 v2 컬러 모드 패턴 제거
// 다음 v2 imports 및 사용을 제거하세요:
import { ColorModeScript } from "@chakra-ui/react" // ❌
import { useColorMode } from "@chakra-ui/react" // ❌ (next-themes 사용)
import { useColorModeValue } from "@chakra-ui/react" // ❌ (CSS 토큰 사용)
import { DarkMode, LightMode } from "@chakra-ui/react" // ❌
// _document.tsx에서도 제거:
;<ColorModeScript initialColorMode={theme.config.initialColorMode} /> // ❌
v3 컬러 모드 접근 방식
컬러 모드는 생성된 Provider를 통해 next-themes에서 처리합니다. 활성 컬러 모드에 자동으로 반응하는 시맨틱 토큰을 사용하세요:
// Chakra 시맨틱 토큰 사용 — 다크 모드에서 자동으로 변경됨
<Box color="fg.default" bg="bg.subtle">
...
</Box>
컬러 모드 토글을 위해서는 생성된 components/ui/color-mode.tsx 스니펫 또는 next-themes의 useColorMode를 직접 사용하세요.
6단계 — Prop 이름 변경
v3에서는 HTML 및 최신 React 규칙과의 일관성을 위해 다음과 같은 boolean 및 스타일 prop의 이름이 변경되었습니다. codemod가 대부분을 처리하지만, 이후 수동으로 확인하세요.
Boolean props
| v2 | v3 |
|---|---|
isOpen | open |
defaultIsOpen | defaultOpen |
isDisabled | disabled |
isInvalid | invalid |
isRequired | required |
isReadOnly | readOnly |
isChecked | checked |
isLoaded | loaded |
isIndeterminate | indeterminate |
스타일 및 레이아웃 props
| v2 | v3 |
|---|---|
colorScheme | colorPalette |
noOfLines | lineClamp |
truncated | truncate |
spacing (Stack) | gap |
apply | textStyle 또는 layerStyle |
중첩 스타일 props
// v2 — 중첩 의사 선택자와 함께 sx
<Box sx={{ "&:hover": { color: "blue.500" } }} />
// v3 — "&" 선택자와 함께 css prop
<Box css={{ "&:hover": { color: "blue.500" } }} />
7단계 — 컴포넌트 마이그레이션
이름이 변경된 컴포넌트
| v2 | v3 |
|---|---|
Modal | Dialog |
FormControl | Field |
Select | NativeSelect |
AlertDialog | AlertDialog (복합 컴포넌트, 아래 참고) |
Modal이 가장 흔한 이름 변경입니다 — 모든 <Modal>, <ModalOverlay>, <ModalContent>, <ModalHeader>, <ModalBody>, <ModalFooter>, <ModalCloseButton>은 Dialog.* 복합 파트가 됩니다:
// v2
<Modal isOpen={open} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Title</ModalHeader>
<ModalBody>Body</ModalBody>
<ModalFooter><Button onClick={onClose}>Close</Button></ModalFooter>
</ModalContent>
</Modal>
// v3
<Dialog.Root open={open} onOpenChange={({ open }) => setOpen(open)}>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Header><Dialog.Title>Title</Dialog.Title></Dialog.Header>
<Dialog.Body>Body</Dialog.Body>
<Dialog.Footer><Button onClick={() => setOpen(false)}>Close</Button></Dialog.Footer>
<Dialog.CloseTrigger />
</Dialog.Content>
</Dialog.Positioner>
</Dialog.Root>
복합 컴포넌트 재작성
v3는 일관된 복합 컴포넌트 API를 채택합니다. codemod가 많은 부분을 처리하지만, 복잡한 사용자 정의 사용은 수동 검토가 필요합니다.
Checkbox
// v2
<Checkbox isChecked={val} onChange={fn}>Label</Checkbox>
// v3
<Checkbox.Root checked={val} onCheckedChange={fn}>
<Checkbox.Control><Checkbox.Indicator /></Checkbox.Control>
<Checkbox.Label>Label</Checkbox.Label>
</Checkbox.Root>
Progress
// v2
<Progress value={60} colorScheme="blue" />
// v3
<Progress.Root value={60} colorPalette="blue">
<Progress.Track><Progress.Range /></Progress.Track>
</Progress.Root>
Accordion
// v2
<Accordion><AccordionItem><AccordionButton /><AccordionPanel /></AccordionItem></Accordion>
// v3
<Accordion.Root>
<Accordion.Item value="item-1">
<Accordion.ItemTrigger />
<Accordion.ItemContent />
</Accordion.Item>
</Accordion.Root>
FormControl → Field
// v2
<FormControl isInvalid={!!error} isRequired>
<FormLabel>Email</FormLabel>
<Input type="email" />
<FormErrorMessage>{error}</FormErrorMessage>
<FormHelperText>We'll never share your email.</FormHelperText>
</FormControl>
// v3
<Field.Root invalid={!!error} required>
<Field.Label>Email</Field.Label>
<Input type="email" />
<Field.ErrorText>{error}</Field.ErrorText>
<Field.HelpText>We'll never share your email.</Field.HelpText>
</Field.Root>
모든 FormControl 하위 파트는 Field.*로 매핑됩니다:
FormLabel→Field.LabelFormErrorMessage→Field.ErrorTextFormHelperText→Field.HelpTextFormControlpropsisInvalid,isRequired,isDisabled→invalid,required,disabled
Dialog / Drawer / Menu / Tabs도 동일한 복합 패턴을 따릅니다: ComponentName.Root, .Trigger, .Content, .Item 등을 사용하세요. 각 특정 복합 API에 대해서는 Chakra UI v3 문서를 확인하세요.
Next.js Image 및 Link (@chakra-ui/next-js 대체)
// v2 — @chakra-ui/next-js
import { LinkOverlay } from "@chakra-ui/next-js"
// v3 — asChild 패턴
import NextLink from "next/link"
<ChakraLink asChild><NextLink href="/about">About</NextLink></ChakraLink>
import NextImage from "next/image"
<ChakraImage asChild><NextImage src="..." alt="..." /></ChakraImage>
8단계 — 테마 마이그레이션
styleConfig 및 multiStyleConfig → recipes
// v3 — 단일 컴포넌트 (recipe)
import { defineRecipe } from "@chakra-ui/react"
// v2
const buttonStyle = {
baseStyle: { fontWeight: "bold" },
variants: { solid: { bg: "blue.500" } },
defaultProps: { variant: "solid" },
}
const buttonRecipe = defineRecipe({
base: { fontWeight: "bold" },
variants: { variant: { solid: { bg: "blue.500" } } },
defaultVariants: { variant: "solid" },
})
// v3 — slot recipe
import { defineSlotRecipe } from "@chakra-ui/react"
// v2 — multiStyleConfig (다중 파트 컴포넌트)
const cardStyle = multiStyleConfig({
parts: ["root", "header"],
baseStyle: { root: { bg: "white" }, header: { fontWeight: "bold" } },
})
const cardSlotRecipe = defineSlotRecipe({
slots: ["root", "header"],
base: { root: { bg: "white" }, header: { fontWeight: "bold" } },
})
사용자 정의 토큰을 위한 Typegen
사용자 정의 토큰, 시맨틱 토큰, recipes 또는 slot recipes를 추가한 후, TypeScript 타입을 동기화하려면 typegen을 실행하세요:
npx @chakra-ui/cli typegen ./theme.ts
복잡한 테마 마이그레이션 — 많은 사용자 정의 토큰, 시맨틱 토큰 또는 다중 파트 컴포넌트 스타일이 있는 큰 v2 테마를 이동하는 경우,
chakra-ui-theming스킬을 사용하세요. 이 스킬은 전체 토큰/recipe/slot-recipe API를 심도 있게 다루며, 이 섹션만으로는 충분하지 않습니다.
9단계 — Next.js 관련 사항
App Router
app/layout.tsx에<Provider>를 배치하세요 (Server Component —"use client"불필요)- 생성된
components/ui/provider.tsx에는 이미"use client"가 있음 - 컬러 모드 깜빡임을 방지하려면
<html>에suppressHydrationWarning을 추가하세요 - 전체 앱이나 레이아웃을
"use client"로 감싸지 마세요
Pages Router
// pages/_app.js
import { Provider } from "@/components/ui/provider"
export default function App({ Component, pageProps }) {
return (
<Provider>
<Component {...pageProps} />
</Provider>
)
}
pages/_document.tsx에서 ColorModeScript를 제거하세요 — v3에서는 사용되지 않습니다.
10단계 — 검증 체크리스트
마이그레이션 완료 후 다음을 확인하세요:
- 의존성 재설치:
npm install/pnpm install - TypeScript:
npx tsc --noEmit— 모든 타입 오류 해결 - 린트:
npm run lint - 빌드:
npm run build - 컬러 모드 토글 시각적 확인 (라이트 ↔ 다크)
- 대화형 컴포넌트 테스트: Dialog, Drawer, Menu, Tabs, Accordion
- 폼 컴포넌트 테스트: Checkbox, Select/NativeSelect, Input, Radio
- 주요 페이지에서 시각적 회귀 확인
- 코드베이스에서 남아 있는 v2 imports 검색:
grep -r "ColorModeScript\|useColorModeValue\|extendTheme\|styleConfig\|@chakra-ui/icons\|@chakra-ui/next-js" src/
명확화 질문 (컨텍스트가 불분명할 때)
사용자의 버전, 프레임워크 또는 범위가 모호한 경우 다음을 물어보세요:
- "현재
@chakra-ui/react버전이 어떻게 되나요?" - "Next.js App Router, Pages Router, Vite, 또는 일반 React를 사용하고 있나요?"
- "전체 코드베이스를 마이그레이션하고 있나요, 아니면 특정 컴포넌트만 해당되나요?"
묻지 않고 진행하는 경우 가정을 명확히 밝히세요.