Skip to content
Frontend
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
127k2 skills

Claude Code

$ npx -y skills add shadcn-ui/ui --skill migrate-radix-to-base --agent claude-code

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
Stats
127,886
Stars
11,338
Forks
Active
Maintenance
TypeScript
Language
MIT
License
Last commit
Created

Repo: shadcn-ui/ui

@shadcn-ui
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.

Stars on GitHub

Momentum

stars in total
127.1k
Star history of shadcn-ui/ui on GitHub, a chart by star-history.com

Other skills on ui.

shadcn

shadcn

Manages shadcn components and projects — adding, searching, fixing, debugging, styling, and composing UI, including chat…

@shadcn-ui@shadcn-uiInstall Skill

More skills from other plugins.

next-bundle-optimizer
Auto-invoked

next-bundle-optimizer

Audit and reduce Next.js browser initial-load work. Use for slow route startup, oversized client bundles, duplicate browser…

nextjs1d143k
@vercel@vercelInstall Skill
chrome-release-cls

chrome-release-cls

Given a Chrome Releases blog post URL (chromereleases.googleblog.com), extract every CVE/bug and find the underlying Gerrit CL…

electron1d124k
@electron@electronInstall Skill
taste-skill
Auto-invoked

taste-skill

tasteskill v2, the anti-slop frontend skill. Art direction for websites, distilled from a study of 247 curated gallery sites (One…

@leonxlnx@leonxlnxInstall Skill
angular-developer

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, services, or HTTP…

angular11d101k
@angular@angularInstall Skill

Questions about migrate-radix-to-base.

Which coding agents can use migrate-radix-to-base?
migrate-radix-to-base installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.