Communitygithub.com

shadcn-ui/ui

Migra proyectos y componentes de React de Radix UI a Base UI. Úsalo cuando se pida migrar desde radix, mover a base-ui, convertir primitivas de radix, o cambiar la biblioteca base de un proyecto shadcn. Maneja componentes individuales ('migrar accordion') y proyectos completos.

¿Qué es ui?

Esta habilidad automatiza la migración de componentes de interfaz de usuario de Radix UI a Base UI (@base-ui/react) en proyectos React, especialmente aquellos basados en shadcn/ui. Es útil para desarrolladores que desean actualizar su stack de componentes primitivos sin reescribir manualmente cada wrapper o punto de consumo. Soporta tanto migraciones progresivas (componente por componente) como de proyecto completo, preservando personalizaciones existentes mediante fusión a tres bandas. Funciona con estilos shadcn conocidos (radix-<style>) usando el CLI de shadcn como 'par dorado' preferido, y como fallback transforma código Radix escrito a mano con tablas de propiedades, mapeo de clases y patrones universales. Incluye verificación de tipo por archivo, compilación por lote, informes detallados en .migration/, y reglas estrictas para no tocar bibliotecas no Radix (cmdk, vaul, sonner, etc.) ni cambiar comportamiento silenciosamente.

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

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Migración de Radix UI a Base UI

Migras wrappers de shadcn, composiciones Radix hechas a mano y sus consumidores a @base-ui/react, manteniendo el proyecto compilable en cada paso. Sé preciso; nunca adivines un mapeo. Cuando una prop o parte no esté en estos archivos de referencia, revisa node_modules/@base-ui/react/**/*.d.ts antes de transformar, y registra las brechas en el informe.

Preflight (siempre)

  1. npx shadcn@latest info --json (o el runner del proyecto): da la base actual, STYLE (ej. radix-lyra), versión de tailwind, alias, componentes instalados y gestor de paquetes. Confía en ello sobre la inferencia.
  2. Detecta el gestor de paquetes (campo packageManager / lockfile: pnpm-lock.yaml, bun.lock, yarn.lock, package-lock.json) y úsalo para CADA instalación. Nunca dejes un lockfile obsoleto.
  3. Exige un árbol git limpio; trabaja en una rama; un commit por componente.
  4. Verificación base ANTES de tocar dependencias: ejecuta el typecheck/build del proyecto para que las fallas preexistentes nunca te sean atribuidas.
  5. Instala @base-ui/react junto a radix. Los paquetes Radix se eliminan solo después de migrar el ÚLTIMO componente (ambos coexisten bien).

Estrategia: par dorado primero, motor de transformación segundo

  • Par dorado vía CLI (preferido). Si el proyecto es shadcn con un estilo conocido (radix-<style>), el propio CLI de shadcn es el ejecutor del par dorado:
    1. Clasifica CADA wrapper de ui PRIMERO: compara el archivo del usuario con su origen estándar, usando el estilo de components.json TEXTUAL en la URL (https://ui.shadcn.com/r/styles/<style>/<component>.json, files[0].content). Esto funciona para estilos prefijados (radix-nova) Y los heredados sin prefijo (new-york, new-york-v4, default), que aún se sirven.
    2. Modo PROYECTO COMPLETO: cambia ahora el estilo de components.json de radix-<style> a base-<style>. Modo PROGRESIVO: NO lo cambies aún (el proyecto sigue siendo mayoritariamente radix; el cambio ocurre una vez, después del último componente); obtén las variantes base directamente por URL (https://ui.shadcn.com/r/styles/base-<style>/<component>.json).
    3. Wrappers SIN personalizar, modo proyecto completo: shadcn add <component> --overwrite entrega la variante base con la resolución exacta de iconos/fuentes/ajustes preestablecidos del proyecto. Nunca hagas --all --overwrite; ve componente por componente, o te ahogarás en desviaciones de versión del registro no relacionadas. Modo PROGRESIVO: nunca uses --overwrite (destruye el original que los consumidores aún importan); escribe el contenido de la variante base obtenida en <component>-base.tsx.
    4. Wrappers PERSONALIZADOS: obtén la variante base y reproduce el diff del usuario sobre ella (sus personalizaciones deben SOBREVIVIR; --overwrite las destruiría). Implementación mecánica que funciona a escala: git merge-file user.tsx radix-golden.tsx base-golden.tsx (fusión a tres bandas, radix golden como ancestro) resuelve automáticamente la mayoría de archivos; resuelve conflictos manualmente con las tablas de referencia.
    5. BARRIDO OBLIGATORIO de restos en CADA archivo del par dorado, incluidos los que se fusionaron "limpios": grep -n "radix-ui\|@radix-ui\|IconPlaceholder" por archivo. El registro a veces reordena funciones entre variantes, lo que hace que las fusiones a tres bandas reporten cero conflictos mientras dejan fragmentos radix obsoletos. Una fusión limpia NO es prueba de un archivo limpio. Esto es más confiable que reconstruir transformaciones; úsalo siempre que el par exista. El código de aplicación/consumidor no tiene mecanismo CLI: migra siempre a mano contra consumer-props.md.
  • Estilos heredados (new-york, new-york-v4, default): solo clasificación, sin reproducción. Estos no tienen contraparte base (no existe base-new-york), y reorientarlos a una variante base- cambiaría el estilo de la aplicación del usuario. Usa el radix golden SOLO para detectar personalizaciones, luego ejecuta el motor de transformación sobre el archivo PROPIO del usuario: reconfigura primitivas, mantén sus clases exactas, aplica renombres de mapeo de clases. Su aspecto sigue siendo suyo. Al final de una migración de proyecto completo heredada, MARCA (no corrijas): el nombre del estilo aún se lee como radix para el CLI, por lo que futuros shadcn add entregarán variantes radix; el usuario decide si cambiar el estilo o agregar manualmente.
  • Motor de transformación (fallback). Código Radix hecho a mano, proyectos no shadcn, estilos desconocidos: transforma usando universal-patterns.md (imports en AMBAS formas: radix-ui y @radix-ui/react-*; asChild->render con el ejemplo trabajado; Portal>Positioner>Popup; la regla FORWARD del positioner; renombres de partes), las tablas de props por familia (overlays.md, menus.md, form-controls.md, disclosure.md, display-misc.md), class-mapping.md para reescrituras de data-attribute/CSS-var, y wrapper-shapes.md para las formas objetivo exactas (flecha de tooltip, valores predeterminados de SubContent, anatomía de select).

Modos

Progresivo (predeterminado). "Migrar accordion" = un componente, strangler-fig:

  1. Detecta primero el estado en progreso: un <component>-base.tsx existente, consumidores divididos entre imports viejos/nuevos. Los archivos SON el estado; reanuda, nunca reinicies.
  2. Si el componente importa otros wrappers de ui que aún están en radix (select -> button), DETENTE y recomienda migrar esos primero, de abajo hacia arriba.
  3. Escribe la versión migrada en <component>-base.tsx (original intacto; contenido del par dorado obtenido por URL, o transformado a mano, según la estrategia anterior); typecheck. Reapunta los consumidores UNO A LA VEZ (imports + las props del sitio de llamada en consumer-props.md); typecheck cada uno. Cuando ningún consumidor importe el original: bórralo, renombra -base -> original, revierte los imports, verificación final, commit. Cuando el ÚLTIMO wrapper radix en el proyecto esté finalizado, cambia components.json a base-<style> y elimina las dependencias radix.

Proyecto completo (solo cuando se pida explícitamente): el mismo trabajo por componente en orden de dependencia (wrappers hoja/compartidos como button y label primero). Después de los wrappers, barre TODO el código de la aplicación contra consumer-props.md — la superficie de rotura en los sitios de llamada es mucho mayor que asChild. Luego elimina las dependencias radix, instala, compilación completa.

Reglas estrictas

  • NUNCA toques bibliotecas no Radix ni sus wrappers: cmdk (command), vaul (drawer), sonner, input-otp, react-day-picker (calendar), recharts (chart). Infórmalos como intencionalmente no tocados.
  • Sin contraparte en Base UI: AspectRatio -> div con CSS aspect-ratio; Label -> etiqueta <label> nativa; VisuallyHidden -> sr-only; Direction -> Direction Provider (prop direction, no dir). Popover Anchor y NavigationMenu Indicator no tienen equivalente: paso inerte + bandera.
  • button.tsx migra a la primitiva REAL de @base-ui/react/button, nunca un wrapper useRender hecho a mano.
  • Los cambios de comportamiento son MARCADOS, nunca parcheados en silencio (activación manual de tabs, elementos de menú que no se cierran al hacer clic, retardo de 50ms en nav-menu). El objetivo es un Base UI idiomático que coincida con el registro base de shadcn.
  • Informe honesto: los archivos omitidos/revertidos se listan como marcados, nunca como migrados. Las fallas preexistentes se nombran como preexistentes.

Verificar e informar

Typecheck por archivo, build por lote, build completo al final contra la línea base.

Los informes residen en un directorio .migration/ en la raíz del proyecto, UN ARCHIVO POR COMPONENTE: .migration/<component>.md (ej. .migration/accordion.md). Reglas:

  • Cada ejecución escribe (o sobrescribe completamente) el archivo para cada componente que migró. Volver a ejecutar un componente reemplaza su informe; nunca toques los archivos de otros componentes.
  • Una ejecución de múltiples componentes ("migrar alert-dialog y dropdown-menu") escribe un archivo por componente, cada uno autocontenido; las notas compartidas de barrido de consumidores se repiten en cada archivo afectado.
  • El modo proyecto completo escribe los archivos por componente más .migration/project.md (intercambio de dependencias, resumen del barrido de código de aplicación, resultado final del build).
  • NO hay archivo de índice. El estado de la migración se deriva del disco, no se mantiene: escanea el directorio ui del proyecto (el alias ui de shadcn info, ej. components/ui o src/components/ui) en busca de imports radix restantes cuando se pregunte "qué queda". Termina cada resumen de ejecución con ese recuento derivado ("Quedan N wrappers en Radix").

Cada .migration/<component>.md usa EXACTAMENTE esta estructura (está documentada públicamente; los informes deben coincidir con ella):

# <component>

<fecha, estrategia utilizada (par dorado vía CLI / fusión / motor), veredicto de una línea>

## Cambiado

<cada archivo tocado, con qué cambió y por qué; incluye archivo:línea para cualquier cosa notable. Confirma que el barrido de restos está limpio: grep -n "radix-ui\|@radix-ui" en los archivos de este componente>

## Dejado intacto

<archivos que parecen relacionados pero no se tocaron intencionalmente, con la razón (cmdk/vaul/sonner no son radix; desviación no relacionada; etc.)>

## Cambios de comportamiento

<diferencias que compilan bien pero actúan de manera diferente; marcadas, nunca parcheadas (activación de tabs, cierre al hacer clic en menú, retardos...). Sección vacía si no hay ninguna>

## Verificar a mano

<lista de verificación QA manual breve para esta familia de primitivas: retorno de foco en diálogos, navegación por teclado + typeahead en menús/select, sensación de retardo en tooltip, eventos de commit de slider. Pasos concretos, un minuto de clics>

Individual skills in this repo

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

Skills relacionados