Communitygithub.com

shadcn-ui/ui

React 프로젝트와 컴포넌트를 Radix UI에서 Base UI로 마이그레이션합니다. radix에서 마이그레이션, base-ui로 전환, radix 프리미티브 변환, 또는 shadcn 프로젝트의 기본 라이브러리 변경 요청 시 사용하세요. 단일 컴포넌트(예: "아코디언 마이그레이션") 및 전체 프로젝트를 처리합니다.

ui란 무엇인가요?

이 기술은 shadcn/ui 기반 React 프로젝트와 커스텀 Radix UI 컴포넌트를 `@base-ui/react`로 마이그레이션하는 자동화된 도구입니다. CLI 기반 '골든 페어(Golden Pair)' 방식을 선호하여 원본과 대상 간의 정확한 매핑을 보장하며, 커스터마이즈된 래퍼(wrapper)의 경우 3-way 병합(`git merge-file`)으로 사용자 변경 사항을 보존합니다. CLI 골든 페어가 불가능한 레거시 스타일(new-york 등)이나 비-shadcn 프로젝트는 변환 엔진(transformation engine)을 통해 수동으로 변환합니다. 전체 프로젝트 모드와 점진적(progressive) 모드를 모두 지원하며, 점진적 모드에서는 각 컴포넌트를 하나씩 `-base.tsx` 파일로 변환한 후 원본을 대체합니다. 모든 변환은 `.migration/` 디렉토리에 컴포넌트별 보고서를 생성하고, 타입체크와 빌드를 각 단계마다 검증하여 안정성을 유지합니다. cmdk, vaul, sonner 등 Base UI에 없는 라이브러리는 의도적으로 건드리지 않으며, 동작 차이는 보고만 하고 무음 패치하지 않습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/shadcn-ui/ui/tree/HEAD/skills/migrate-radix-to-base

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Radix UI -> Base UI 마이그레이션

shadcn 래퍼, 수제 Radix 구성, 그리고 그 소비자들을 @base-ui/react로 마이그레이션하며, 모든 단계에서 프로젝트가 빌드 가능한 상태를 유지합니다. 정확하게 작업하며 매핑을 추측하지 마세요. 참조 파일에 없는 prop 또는 part는 변환 전에 node_modules/@base-ui/react/**/*.d.ts를 확인하고, 발견된 차이점은 보고서에 기록하세요.

사전 점검 (항상 수행)

  1. npx shadcn@latest info --json (또는 프로젝트의 실행기): 현재 베이스, STYLE(예: radix-lyra), tailwind 버전, 별칭, 설치된 컴포넌트, 패키지 매니저를 알려줍니다. 추론보다 이를 신뢰하세요.
  2. 패키지 매니저 감지(packageManager 필드 / 잠금 파일: pnpm-lock.yaml, bun.lock, yarn.lock, package-lock.json) 및 모든 설치에 IT를 사용하세요. 오래된 잠금 파일을 남겨두지 마세요.
  3. 깨끗한 git 트리 필요; 브랜치에서 작업; 컴포넌트당 하나의 커밋.
  4. 의존성을 건드리기 전에 기준 검사: 프로젝트의 타입체크/빌드를 실행하여 사전 존재하는 실패가 절대 귀속되지 않도록 하세요.
  5. @base-ui/react를 radix와 함께 설치하세요. Radix 패키지는 마지막 컴포넌트가 마이그레이션된 후에만 제거됩니다(둘 다 잘 공존합니다).

전략: 골든 페어 우선, 변환 엔진 차선

  • CLI를 통한 골든 페어 (선호). 프로젝트가 알려진 스타일(radix-<style>)의 shadcn인 경우, shadcn CLI 자체가 골든 페어 실행기입니다:
    1. 각 UI 래퍼를 먼저 분류: 사용자 파일을 스톡 원본과 비교(diff), components.json 스타일을 URL에 그대로 사용(https://ui.shadcn.com/r/styles/<style>/<component>.json, files[0].content). 이것은 접두사가 있는 스타일(radix-nova)과 접두사가 없는 레거시(new-york, new-york-v4, default) 모두에서 작동하며, 이들은 모두 여전히 제공됩니다.
    2. 전체 프로젝트 모드: components.json 스타일을 radix-<style> -> base-<style>로 지금 뒤집습니다. 점진적 모드: 아직 뒤집지 마세요(프로젝트는 여전히 대부분 radix입니다; 뒤집기는 마지막 컴포넌트 후에 한 번 발생합니다); 대신 URL로 직접 base 변형을 가져오세요(https://ui.shadcn.com/r/styles/base-<style>/<component>.json).
    3. 손대지 않은(pristine) 래퍼, 전체 프로젝트 모드: shadcn add <component> --overwrite는 프로젝트의 정확한 아이콘/폰트/프리셋 해석으로 base 변형을 제공합니다. 절대 --all --overwrite 벌크 작업을 하지 마세요; 컴포넌트별로 진행하세요, 그렇지 않으면 관련 없는 레지스트리 버전 변경에 빠집니다. 점진적 모드: 절대 --overwrite를 사용하지 마세요(소비자가 여전히 가져오는 원본을 파괴합니다); 대신 가져온 base 변형 내용을 <component>-base.tsx에 작성하세요.
    4. 커스터마이즈된 래퍼: base 변형을 가져와서 그 위에 사용자의 diff를 재생합니다(커스터마이징이 유지되어야 함; --overwrite는 이를 파괴합니다). 대규모로 작동하는 기계적 구현: git merge-file user.tsx radix-golden.tsx base-golden.tsx (3-way 병합, radix 골든을 공통 조상으로)는 대부분의 파일을 자동으로 해결합니다; 충돌은 참조 테이블을 사용하여 수동으로 해결합니다.
    5. 모든 골든 페어 파일에 대해 필수적인 잔여물 검사, "깨끗하게" 병합된 파일 포함: 파일당 grep -n "radix-ui\|@radix-ui\|IconPlaceholder". 레지스트리는 때때로 변형 간에 함수를 재정렬하여, 3-way 병합이 제로 충돌을 보고하면서 오래된 radix 덩어리를 그대로 남겨둘 수 있습니다. 깨끗한 병합이 깨끗한 파일의 증거는 아닙니다. 이는 변환을 재구성하는 것보다 더 안정적입니다; 쌍이 존재할 때마다 사용하세요. 소비자/앱 코드에는 CLI 메커니즘이 없습니다: 항상 consumer-props.md에 대해 수동으로 마이그레이션하세요.
  • 레거시 스타일 (new-york, new-york-v4, default): 분류만, 재생 없음. 이들은 base 대응물이 없으며(base-new-york은 없음), base- 변형으로 재타겟팅하면 사용자 앱의 스타일이 변경됩니다. 커스터마이징을 감지하는 데에만 radix 골든을 사용한 다음, 사용자 자신의 파일에 변환 엔진을 실행합니다: 프리미티브 재연결, 정확한 클래스 유지, 클래스 매핑 이름 변경 적용. 그들의 모양은 그들의 것입니다. 레거시 전체 프로젝트 마이그레이션 끝에, 플래그 표시(수정하지 마세요): 스타일 이름이 여전히 CLI에 radix로 읽히므로, 미래의 shadcn add는 radix 변형을 제공할 것입니다; 사용자는 스타일을 전환할지 아니면 수동으로 추가할지 결정합니다.
  • 변환 엔진 (폴백). 수제 Radix 코드, 비-shadcn 프로젝트, 알 수 없는 스타일: universal-patterns.md(두 형태 모두의 가져오기: radix-ui 및 @radix-ui/react-*; asChild->렌더 작업 예제 포함; Portal>Positioner>Popup; positioner FORWARD 규칙; part 이름 변경), 패밀리별 props 테이블(overlays.md, menus.md, form-controls.md, disclosure.md, display-misc.md), 데이터 속성/CSS 변수 재작성을 위한 class-mapping.md, 정확한 대상 형태를 위한 wrapper-shapes.md(툴팁 화살표, SubContent 기본값, select 해부학)를 사용하여 변환합니다.

모드

점진적 (기본값). "아코디언 마이그레이션" = 하나의 컴포넌트, strangler-fig 패턴:

  1. 먼저 진행 중인 상태 감지: 기존 <component>-base.tsx, 소비자가 이전/새 가져오기로 분할됨. 파일이 상태입니다; 재시작하지 말고 이어서 진행하세요.
  2. 컴포넌트가 여전히 radix에 있는 다른 ui 래퍼를 가져오는 경우(select -> button), 중단하고 먼저 하향식으로 해당 래퍼를 마이그레이션할 것을 권장합니다.
  3. 마이그레이션된 버전을 <component>-base.tsx에 작성(원본은 건드리지 않음; 위 전략에 따라 URL로 가져온 골든 페어 내용 또는 수동 변환); 타입체크. 소비자를 한 번에 하나씩 재지정(가져오기 + consumer-props.md의 호출 사이트 props); 각각 타입체크. 어떤 소비자도 원본을 가져오지 않으면: 삭제, -base -> 원본으로 이름 변경, 가져오기 되돌리기, 최종 확인, 커밋. 프로젝트에서 마지막 radix 래퍼가 최종화되면, components.json을 base-<style>로 뒤집고 radix 의존성을 제거하세요.

전체 프로젝트 (명시적으로 요청된 경우에만): 동일한 컴포넌트별 작업을 의존성 순서로 수행(리프/공유 래퍼인 button과 label 먼저). 래퍼 후, consumer-props.md에 대해 모든 앱 코드를 검사 — 호출 사이트 변경 표면이 asChild보다 훨씬 큽니다. 그런 다음 radix 의존성 제거, 설치, 전체 빌드.

엄격한 규칙

  • 비-radix 라이브러리나 그 래퍼를 절대 건드리지 마세요: cmdk (command), vaul (drawer), sonner, input-otp, react-day-picker (calendar), recharts (chart). 의도적으로 건드리지 않은 것으로 보고하세요.
  • Base UI 대응물 없음: AspectRatio -> CSS aspect-ratio div; Label -> 네이티브 <label>; VisuallyHidden -> sr-only; Direction -> Direction Provider (dir이 아닌 direction prop). Popover Anchor와 NavigationMenu Indicator는 동등한 것이 없습니다: non-functional 통과 + 플래그.
  • button.tsx는 실제 @base-ui/react/button 프리미티브로 마이그레이션되며, 절대 수제 useRender 래퍼로 하지 않습니다.
  • 동작 차이는 플래그 표시되며, 절대 조용히 패치되지 않습니다(탭 수동 활성화, 클릭 시 메뉴 항목 닫힘 없음, nav-menu 50ms 지연). 대상은 shadcn base 레지스트리와 일치하는 관용적인 Base UI입니다.
  • 정직한 보고: 건너뛰거나 되돌린 파일은 마이그레이션된 것으로 표시되지 않고 플래그 표시됩니다. 사전 존재하는 실패는 사전 존재하는 것으로 명명됩니다.

확인 및 보고

파일별 타입체크, 배치별 빌드, 마지막에 기준과 비교한 전체 빌드.

보고서는 프로젝트 루트의 .migration/ 디렉토리에 있으며, 컴포넌트당 하나의 파일: .migration/<component>.md (예: .migration/accordion.md). 규칙:

  • 각 실행은 마이그레이션한 각 컴포넌트에 대한 파일을 작성(또는 완전히 덮어씁니다). 컴포넌트를 다시 실행하면 해당 보고서를 대체합니다; 다른 컴포넌트의 파일은 절대 건드리지 않습니다.
  • 다중 컴포넌트 실행("alert-dialog 및 dropdown-menu 마이그레이션")은 각 컴포넌트당 하나의 자체 포함된 파일을 작성합니다; 공유 소비자 검사 노트는 영향을 받는 모든 파일에서 반복됩니다.
  • 전체 프로젝트 모드는 컴포넌트별 파일과 함께 .migration/project.md(의존성 교체, 앱 코드 검사 요약, 최종 빌드 결과)를 작성합니다.
  • 인덱스 파일은 없습니다. 마이그레이션 상태는 유지되지 않고 디스크에서 파생됩니다: "무엇이 남았습니까?"라는 질문을 받으면 프로젝트의 ui 디렉토리(shadcn info의 ui 별칭, 예: components/ui 또는 src/components/ui)를 스캔하여 남은 radix 가져오기를 확인합니다. 각 실행의 요약을 해당 파생 개수로 끝내세요("N개의 래퍼가 Radix에 남아 있습니다").

각 .migration/<component>.md는 정확히 이 구조를 사용합니다 (공개적으로 문서화됨; 보고서는 일치해야 함):

# <component>

<날짜, 사용된 전략 (golden pair via CLI / merge / engine), 한 줄 평가>

## 변경됨

<건드린 모든 파일, 무엇이 변경되었고 그 이유; 주목할 만한 것은 file:line 포함. 잔여물 검사가 깨끗함을 확인: 이 컴포넌트의 파일에 대해 grep -n "radix-ui\|@radix-ui">

## 건드리지 않음

<관련되어 보이지만 의도적으로 건드리지 않은 파일, 이유 포함(cmdk/vaul/sonner는 radix가 아님; 관련 없는 변경 등)>

## 동작 변경사항

<컴파일은 잘 되지만 다르게 동작하는 차이점; 플래그 표시되었으며, 절대 패치되지 않음(탭 활성화, 메뉴 클릭 시 닫힘, 지연...). 없으면 빈 섹션>

## 수동 확인

<이 프리미티브 패밀리에 대한 짧은 수동 QA 체크리스트: 다이얼로그의 포커스 리턴, 메뉴/선택의 키보드 탐색 + 유형어헤드, 툴팁 지연 느낌, 슬라이더 커밋 이벤트. 구체적인 단계, 1분 클릭>

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

관련 스킬