Skip to content
Development
Skill

/migrate-radix-to-base

Migrates React projects and components from Radix UI to Base UI. Use when asked to migrate from radix, move to base-ui, convert radix primitives, or switch a shadcn project's base library. Handles single components ("migrate accordion") and whole projects.

From plugin
ui
121k2 skills
Install
$ npx -y skills add shadcn-ui/ui --skill migrate-radix-to-base --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/migrate-radix-to-base

Context preview

The summary Claude sees to decide when to auto-load this skill.

Migrates React projects and components from Radix UI to Base UI. Use when asked to migrate from radix, move to base-ui, convert radix primitives, or switch a shadcn project's base library. Handles single components ("migrate accordion") and whole projects.

SKILL.md

migrate-radix-to-base.SKILL.md
name: migrate-radix-to-base
description: Migrates React projects and components from Radix UI to Base UI. Use when asked to migrate from radix, move to base-ui, convert radix primitives, or switch a shadcn project's base library. Handles single components ("migrate accordion") and whole projects.

Radix UI -> Base UI migration

You migrate shadcn wrappers, hand-rolled radix compositions, and their consumers to `@base-ui/react`, keeping the project buildable at every step. Be precise; never guess a mapping. When a prop or part is not in these reference files, check `node_modules/@base-ui/react/**/*.d.ts` before transforming, and record gaps in the report.

Preflight (always)

1. `npx shadcn@latest info --json` (or the project's runner): gives the current base, STYLE (e.g. `radix-lyra`), tailwind version, aliases, installed components, and package manager. Trust it over inference. 2. Detect the package manager (packageManager field / lockfile: pnpm-lock.yaml, bun.lock, yarn.lock, package-lock.json) and use IT for every install. Never leave a stale lockfile. 3. Require a clean git tree; work on a branch; one commit per component. 4. Baseline check BEFORE touching dependencies: run the project's typecheck/build so pre-existing failures are never attributed to you. 5. Install `@base-ui/react` alongside radix. Radix packages are removed only after the LAST component is migrated (both coexist fine).

Strategy: golden pair first, transformation engine second

  • **Golden pair via the CLI (preferred).** If the project is shadcn with a

known style (`radix-<style>`), the shadcn CLI itself is the golden-pair executor: 1. Classify each ui wrapper FIRST: diff the user's file against its stock origin, using the components.json style VERBATIM in the URL (`https://ui.shadcn.com/r/styles/<style>/<component>.json`, files[0].content). This works for prefixed styles (radix-nova) AND legacy unprefixed ones (new-york, new-york-v4, default), which are all still served. 2. WHOLE-PROJECT mode: flip `components.json` style `radix-<style>` -> `base-<style>` now. PROGRESSIVE mode: do NOT flip yet (the project is still mostly radix; the flip happens once, after the last component); fetch base variants directly by URL instead (`https://ui.shadcn.com/r/styles/base-<style>/<component>.json`). 3. PRISTINE wrappers, whole-project mode: `shadcn add <component> --overwrite` delivers the base variant with the project's exact icon/font/preset resolution. Never bulk `--all --overwrite`; go component by component, or you drown in unrelated registry version drift. PROGRESSIVE mode: never use `--overwrite` (it destroys the original that consumers still import); write the fetched base variant content to `<component>-base.tsx` instead. 4. CUSTOMIZED wrappers: fetch the base variant and replay the user's diff onto it (their customizations must SURVIVE; `--overwrite` would destroy them). Mechanical implementation that works at scale: `git merge-file user.tsx radix-golden.tsx base-golden.tsx` (three-way merge, radix golden as ancestor) auto-resolves most files; hand-resolve conflicts with the reference tables. 5. MANDATORY leftover sweep on EVERY golden-pair file, including ones that merged "clean": `grep -n "radix-ui\|@radix-ui\|IconPlaceholder"` per file. The registry sometimes reorders functions between variants, which makes three-way merges report zero conflicts while leaving stale radix hunks in place. A clean merge is NOT proof of a clean file. This is more reliable than reconstructing transforms; use it whenever the pair exists. Consumer/app code has no CLI mechanism: always hand-migrate it against `consumer-props.md`.

  • **Legacy styles (new-york, new-york-v4, default): classification only, no

replay.** These have no base counterpart (there is no base-new-york), and retargeting onto a base-<style> variant would restyle the user's app. Use the radix golden ONLY to detect customizations, then run the transformation engine on the user's OWN file: rewire primitives, keep their exact classes, apply class-mapping renames. Their look stays theirs. At the end of a legacy whole-project migration, FLAG (do not fix): the style name still reads as radix to the CLI, so future `shadcn add` will deliver radix variants; the user decides whether to switch style or add manually.

  • **Transformation engine (fallback).** Hand-rolled radix code, non-shadcn

projects, unknown styles: transform using `universal-patterns.md` (imports in BOTH forms: `radix-ui` and `@radix-ui/react-*`; asChild->render with the worked example; Portal>Positioner>Popup; the positioner FORWARD rule; part renames), the per-family props tables (`overlays.md`, `menus.md`, `form-controls.md`, `disclosure.md`, `display-misc.md`), `class-mapping.md` for data-attribute/CSS-var rewrites, and `wrapper-shapes.md` for exact target shapes (tooltip arrow, SubContent defaults, select anatomy).

Modes

**Progressive (default).** "Migrate accordion" = one component, strangler-fig: 1. Detect in-progress state first: an existing `<component>-base.tsx`, consumers split between old/new imports. The files ARE the state; resume, never restart. 2. If the component imports other ui wrappers still on radix (select -> button), STOP and recommend migrating those first, bottom-up. 3. Write the migrated version to `<component>-base.tsx` (original untouched; golden-pair content fetched by URL, or transformed by hand, per the strategy above); typecheck. Repoint consumers ONE AT A TIME (imports + the call-site props in `consumer-props.md`); typecheck each. When no consumer imports the original: delete it, rename `-base` -> original, flip imports back, final check, commit. When the LAST radix wrapper in the project is finalized, flip `components.json` to `base-<style>` and remove

Read more
Ships withui

A set of beautifully designed components that you can customize, extend, and build on. Start here then make it your own. Open Source. Open Code. Use this to build your own component library.

Get the whole plugin
Stats
120,977
Stars
9,793
Forks
Active
Maintenance
TypeScript
Language
MIT
License
3h ago
Last commit
3y ago
Created

Repo: shadcn-ui/ui