[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-shadcn-ui-migrate-radix-to-base":3,"mdc--t1cfo0-key":47,"related-org-shadcn-ui-migrate-radix-to-base":938,"related-repo-shadcn-ui-migrate-radix-to-base":958},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":26,"repoUrl":27,"updatedAt":28,"license":29,"forks":30,"topics":31,"repo":42,"sourceUrl":45,"mdContent":46},"migrate-radix-to-base","migrate React components from 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.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"shadcn-ui","shadcn\u002Fui","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fshadcn-ui.png",[12,16,19,20,23],{"name":13,"slug":14,"type":15},"React","react","tag",{"name":17,"slug":18,"type":15},"Migration","migration",{"name":9,"slug":8,"type":15},{"name":21,"slug":22,"type":15},"UI Components","ui-components",{"name":24,"slug":25,"type":15},"Frontend","frontend",118955,"https:\u002F\u002Fgithub.com\u002Fshadcn-ui\u002Fui","2026-07-18T05:48:33.480459",null,9487,[32,33,34,35,36,14,37,38,39,40,41],"base-ui","components","laravel","nextjs","radix-ui","shadcn","tailwindcss","tanstack","ui","vite",{"repoUrl":27,"stars":26,"forks":30,"topics":43,"description":44},[32,33,34,35,36,14,37,38,39,40,41],"A set of beautifully-designed, accessible components and a code distribution platform. Works with your favorite frameworks. Open Source. Open Code.","https:\u002F\u002Fgithub.com\u002Fshadcn-ui\u002Fui\u002Ftree\u002FHEAD\u002Fskills\u002Fmigrate-radix-to-base","---\nname: migrate-radix-to-base\ndescription: 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.\n---\n\n# Radix UI -> Base UI migration\n\nYou migrate shadcn wrappers, hand-rolled radix compositions, and their\nconsumers to `@base-ui\u002Freact`, keeping the project buildable at every step.\nBe precise; never guess a mapping. When a prop or part is not in these\nreference files, check `node_modules\u002F@base-ui\u002Freact\u002F**\u002F*.d.ts` before\ntransforming, and record gaps in the report.\n\n## Preflight (always)\n\n1. `npx shadcn@latest info --json` (or the project's runner): gives the\n   current base, STYLE (e.g. `radix-lyra`), tailwind version, aliases,\n   installed components, and package manager. Trust it over inference.\n2. Detect the package manager (packageManager field \u002F lockfile:\n   pnpm-lock.yaml, bun.lock, yarn.lock, package-lock.json) and use IT for\n   every install. Never leave a stale lockfile.\n3. Require a clean git tree; work on a branch; one commit per component.\n4. Baseline check BEFORE touching dependencies: run the project's\n   typecheck\u002Fbuild so pre-existing failures are never attributed to you.\n5. Install `@base-ui\u002Freact` alongside radix. Radix packages are removed only\n   after the LAST component is migrated (both coexist fine).\n\n## Strategy: golden pair first, transformation engine second\n\n- **Golden pair via the CLI (preferred).** If the project is shadcn with a\n  known style (`radix-\u003Cstyle>`), the shadcn CLI itself is the golden-pair\n  executor:\n  1. Classify each ui wrapper FIRST: diff the user's file against its stock\n     origin, using the components.json style VERBATIM in the URL\n     (`https:\u002F\u002Fui.shadcn.com\u002Fr\u002Fstyles\u002F\u003Cstyle>\u002F\u003Ccomponent>.json`,\n     files[0].content). This works for prefixed styles (radix-nova) AND\n     legacy unprefixed ones (new-york, new-york-v4, default), which are all\n     still served.\n  2. WHOLE-PROJECT mode: flip `components.json` style `radix-\u003Cstyle>` ->\n     `base-\u003Cstyle>` now. PROGRESSIVE mode: do NOT flip yet (the project is\n     still mostly radix; the flip happens once, after the last component);\n     fetch base variants directly by URL instead\n     (`https:\u002F\u002Fui.shadcn.com\u002Fr\u002Fstyles\u002Fbase-\u003Cstyle>\u002F\u003Ccomponent>.json`).\n  3. PRISTINE wrappers, whole-project mode: `shadcn add \u003Ccomponent>\n     --overwrite` delivers the base variant with the project's exact\n     icon\u002Ffont\u002Fpreset resolution. Never bulk `--all --overwrite`; go\n     component by component, or you drown in unrelated registry version\n     drift. PROGRESSIVE mode: never use `--overwrite` (it destroys the\n     original that consumers still import); write the fetched base variant\n     content to `\u003Ccomponent>-base.tsx` instead.\n  4. CUSTOMIZED wrappers: fetch the base variant and replay the user's diff\n     onto it (their customizations must SURVIVE; `--overwrite` would destroy\n     them). Mechanical implementation that works at scale:\n     `git merge-file user.tsx radix-golden.tsx base-golden.tsx` (three-way\n     merge, radix golden as ancestor) auto-resolves most files; hand-resolve\n     conflicts with the reference tables.\n  5. MANDATORY leftover sweep on EVERY golden-pair file, including ones that\n     merged \"clean\": `grep -n \"radix-ui\\|@radix-ui\\|IconPlaceholder\"` per\n     file. The registry sometimes reorders functions between variants, which\n     makes three-way merges report zero conflicts while leaving stale radix\n     hunks in place. A clean merge is NOT proof of a clean file.\n  This is more reliable than reconstructing transforms; use it whenever the\n  pair exists. Consumer\u002Fapp code has no CLI mechanism: always hand-migrate it\n  against `consumer-props.md`.\n- **Legacy styles (new-york, new-york-v4, default): classification only, no\n  replay.** These have no base counterpart (there is no base-new-york), and\n  retargeting onto a base-\u003Cstyle> variant would restyle the user's app. Use\n  the radix golden ONLY to detect customizations, then run the transformation\n  engine on the user's OWN file: rewire primitives, keep their exact classes,\n  apply class-mapping renames. Their look stays theirs. At the end of a\n  legacy whole-project migration, FLAG (do not fix): the style name still\n  reads as radix to the CLI, so future `shadcn add` will deliver radix\n  variants; the user decides whether to switch style or add manually.\n- **Transformation engine (fallback).** Hand-rolled radix code, non-shadcn\n  projects, unknown styles: transform using `universal-patterns.md` (imports\n  in BOTH forms: `radix-ui` and `@radix-ui\u002Freact-*`; asChild->render with the\n  worked example; Portal>Positioner>Popup; the positioner FORWARD rule; part\n  renames), the per-family props tables (`overlays.md`, `menus.md`,\n  `form-controls.md`, `disclosure.md`, `display-misc.md`), `class-mapping.md`\n  for data-attribute\u002FCSS-var rewrites, and `wrapper-shapes.md` for exact\n  target shapes (tooltip arrow, SubContent defaults, select anatomy).\n\n## Modes\n\n**Progressive (default).** \"Migrate accordion\" = one component, strangler-fig:\n1. Detect in-progress state first: an existing `\u003Ccomponent>-base.tsx`,\n   consumers split between old\u002Fnew imports. The files ARE the state; resume,\n   never restart.\n2. If the component imports other ui wrappers still on radix (select ->\n   button), STOP and recommend migrating those first, bottom-up.\n3. Write the migrated version to `\u003Ccomponent>-base.tsx` (original untouched;\n   golden-pair content fetched by URL, or transformed by hand, per the\n   strategy above); typecheck. Repoint consumers ONE AT A TIME (imports + the\n   call-site props in `consumer-props.md`); typecheck each. When no consumer\n   imports the original: delete it, rename `-base` -> original, flip imports\n   back, final check, commit. When the LAST radix wrapper in the project is\n   finalized, flip `components.json` to `base-\u003Cstyle>` and remove radix deps.\n\n**Whole project** (only when explicitly asked): same per-component work in\ndependency order (leaf\u002Fshared wrappers like button and label first). After\nwrappers, sweep ALL app code against `consumer-props.md` — the call-site\nbreak surface is much larger than asChild. Then remove radix deps, install,\nfull build.\n\n## Hard rules\n\n- NEVER touch non-radix libraries or their wrappers: cmdk (command), vaul\n  (drawer), sonner, input-otp, react-day-picker (calendar), recharts (chart).\n  Report them as intentionally untouched.\n- No Base UI counterpart: AspectRatio -> CSS aspect-ratio div; Label ->\n  native `\u003Clabel>`; VisuallyHidden -> `sr-only`; Direction -> Direction\n  Provider (`direction` prop, not `dir`). Popover Anchor and NavigationMenu\n  Indicator have no equivalent: inert passthrough + flag.\n- `button.tsx` migrates to the REAL `@base-ui\u002Freact\u002Fbutton` primitive, never\n  a hand-rolled useRender wrapper.\n- Behavior deltas are FLAGGED, never silently patched (tabs manual\n  activation, menu items not closing on click, nav-menu 50ms delay). The\n  target is idiomatic Base UI matching the shadcn base registry.\n- Honest reporting: skipped\u002Freverted files are listed as flagged, never as\n  migrated. Pre-existing failures are named as pre-existing.\n\n## Verify and report\n\nTypecheck per file, build per batch, full build at the end vs the baseline.\n\nReports live in a `.migration\u002F` directory at the project root, ONE FILE PER\nCOMPONENT: `.migration\u002F\u003Ccomponent>.md` (e.g. `.migration\u002Faccordion.md`).\nRules:\n- Each run writes (or fully overwrites) the file for each component it\n  migrated. Re-running a component replaces its report; never touch other\n  components' files.\n- A multi-component run (\"migrate alert-dialog and dropdown-menu\") writes one\n  file per component, each self-contained; shared consumer-sweep notes are\n  repeated in every affected file.\n- Whole-project mode writes the per-component files plus\n  `.migration\u002Fproject.md` (dependency swap, app-code sweep summary, final\n  build result).\n- There is NO index file. Migration status is derived from disk, not\n  maintained: scan the project's ui directory (the `ui` alias from shadcn\n  info, e.g. components\u002Fui or src\u002Fcomponents\u002Fui) for remaining radix imports\n  when asked \"what's left\". End every run's summary with that derived count\n  (\"N wrappers remain on Radix\").\n\nEach `.migration\u002F\u003Ccomponent>.md` uses EXACTLY this structure (it is\ndocumented publicly; reports must match it):\n\n```md\n# \u003Ccomponent>\n\n\u003Cdate, strategy used (golden pair via CLI \u002F merge \u002F engine), one-line verdict>\n\n## Changed\n\n\u003Cevery file touched, with what changed and why; include file:line for\nanything notable. Confirm the leftover scan is clean:\ngrep -n \"radix-ui\\|@radix-ui\" on this component's files>\n\n## Left alone\n\n\u003Cfiles that look related but were intentionally not touched, with the reason\n(cmdk\u002Fvaul\u002Fsonner are not radix; unrelated drift; etc.)>\n\n## Behavior changes\n\n\u003Cdifferences that compile fine but act differently; flagged, never patched\n(tabs activation, menu close-on-click, delays...). Empty section if none>\n\n## Verify by hand\n\n\u003Cshort manual QA checklist for this primitive family: focus return on\ndialogs, keyboard nav + typeahead on menus\u002Fselect, tooltip delay feel,\nslider commit events. Concrete steps, one minute of clicking>\n```\n",{"data":48,"body":49},{"name":4,"description":6},{"type":50,"children":51},"root",[52,61,84,91,142,148,414,420,430,491,508,514,588,594,599,628,666,678,933],{"type":53,"tag":54,"props":55,"children":57},"element","h1",{"id":56},"radix-ui-base-ui-migration",[58],{"type":59,"value":60},"text","Radix UI -> Base UI migration",{"type":53,"tag":62,"props":63,"children":64},"p",{},[65,67,74,76,82],{"type":59,"value":66},"You migrate shadcn wrappers, hand-rolled radix compositions, and their\nconsumers to ",{"type":53,"tag":68,"props":69,"children":71},"code",{"className":70},[],[72],{"type":59,"value":73},"@base-ui\u002Freact",{"type":59,"value":75},", keeping the project buildable at every step.\nBe precise; never guess a mapping. When a prop or part is not in these\nreference files, check ",{"type":53,"tag":68,"props":77,"children":79},{"className":78},[],[80],{"type":59,"value":81},"node_modules\u002F@base-ui\u002Freact\u002F**\u002F*.d.ts",{"type":59,"value":83}," before\ntransforming, and record gaps in the report.",{"type":53,"tag":85,"props":86,"children":88},"h2",{"id":87},"preflight-always",[89],{"type":59,"value":90},"Preflight (always)",{"type":53,"tag":92,"props":93,"children":94},"ol",{},[95,115,120,125,130],{"type":53,"tag":96,"props":97,"children":98},"li",{},[99,105,107,113],{"type":53,"tag":68,"props":100,"children":102},{"className":101},[],[103],{"type":59,"value":104},"npx shadcn@latest info --json",{"type":59,"value":106}," (or the project's runner): gives the\ncurrent base, STYLE (e.g. ",{"type":53,"tag":68,"props":108,"children":110},{"className":109},[],[111],{"type":59,"value":112},"radix-lyra",{"type":59,"value":114},"), tailwind version, aliases,\ninstalled components, and package manager. Trust it over inference.",{"type":53,"tag":96,"props":116,"children":117},{},[118],{"type":59,"value":119},"Detect the package manager (packageManager field \u002F lockfile:\npnpm-lock.yaml, bun.lock, yarn.lock, package-lock.json) and use IT for\nevery install. Never leave a stale lockfile.",{"type":53,"tag":96,"props":121,"children":122},{},[123],{"type":59,"value":124},"Require a clean git tree; work on a branch; one commit per component.",{"type":53,"tag":96,"props":126,"children":127},{},[128],{"type":59,"value":129},"Baseline check BEFORE touching dependencies: run the project's\ntypecheck\u002Fbuild so pre-existing failures are never attributed to you.",{"type":53,"tag":96,"props":131,"children":132},{},[133,135,140],{"type":59,"value":134},"Install ",{"type":53,"tag":68,"props":136,"children":138},{"className":137},[],[139],{"type":59,"value":73},{"type":59,"value":141}," alongside radix. Radix packages are removed only\nafter the LAST component is migrated (both coexist fine).",{"type":53,"tag":85,"props":143,"children":145},{"id":144},"strategy-golden-pair-first-transformation-engine-second",[146],{"type":59,"value":147},"Strategy: golden pair first, transformation engine second",{"type":53,"tag":149,"props":150,"children":151},"ul",{},[152,309,327],{"type":53,"tag":96,"props":153,"children":154},{},[155,161,163,169,171],{"type":53,"tag":156,"props":157,"children":158},"strong",{},[159],{"type":59,"value":160},"Golden pair via the CLI (preferred).",{"type":59,"value":162}," If the project is shadcn with a\nknown style (",{"type":53,"tag":68,"props":164,"children":166},{"className":165},[],[167],{"type":59,"value":168},"radix-\u003Cstyle>",{"type":59,"value":170},"), the shadcn CLI itself is the golden-pair\nexecutor:\n",{"type":53,"tag":92,"props":172,"children":173},{},[174,195,231,268,288],{"type":53,"tag":96,"props":175,"children":176},{},[177,179,185,187,193],{"type":59,"value":178},"Classify each ui wrapper FIRST: diff the user's file against its stock\norigin, using the components.json style VERBATIM in the URL\n(",{"type":53,"tag":68,"props":180,"children":182},{"className":181},[],[183],{"type":59,"value":184},"https:\u002F\u002Fui.shadcn.com\u002Fr\u002Fstyles\u002F\u003Cstyle>\u002F\u003Ccomponent>.json",{"type":59,"value":186},",\nfiles",{"type":53,"tag":188,"props":189,"children":190},"span",{},[191],{"type":59,"value":192},"0",{"type":59,"value":194},".content). This works for prefixed styles (radix-nova) AND\nlegacy unprefixed ones (new-york, new-york-v4, default), which are all\nstill served.",{"type":53,"tag":96,"props":196,"children":197},{},[198,200,206,208,213,215,221,223,229],{"type":59,"value":199},"WHOLE-PROJECT mode: flip ",{"type":53,"tag":68,"props":201,"children":203},{"className":202},[],[204],{"type":59,"value":205},"components.json",{"type":59,"value":207}," style ",{"type":53,"tag":68,"props":209,"children":211},{"className":210},[],[212],{"type":59,"value":168},{"type":59,"value":214}," ->\n",{"type":53,"tag":68,"props":216,"children":218},{"className":217},[],[219],{"type":59,"value":220},"base-\u003Cstyle>",{"type":59,"value":222}," now. PROGRESSIVE mode: do NOT flip yet (the project is\nstill mostly radix; the flip happens once, after the last component);\nfetch base variants directly by URL instead\n(",{"type":53,"tag":68,"props":224,"children":226},{"className":225},[],[227],{"type":59,"value":228},"https:\u002F\u002Fui.shadcn.com\u002Fr\u002Fstyles\u002Fbase-\u003Cstyle>\u002F\u003Ccomponent>.json",{"type":59,"value":230},").",{"type":53,"tag":96,"props":232,"children":233},{},[234,236,242,244,250,252,258,260,266],{"type":59,"value":235},"PRISTINE wrappers, whole-project mode: ",{"type":53,"tag":68,"props":237,"children":239},{"className":238},[],[240],{"type":59,"value":241},"shadcn add \u003Ccomponent> --overwrite",{"type":59,"value":243}," delivers the base variant with the project's exact\nicon\u002Ffont\u002Fpreset resolution. Never bulk ",{"type":53,"tag":68,"props":245,"children":247},{"className":246},[],[248],{"type":59,"value":249},"--all --overwrite",{"type":59,"value":251},"; go\ncomponent by component, or you drown in unrelated registry version\ndrift. PROGRESSIVE mode: never use ",{"type":53,"tag":68,"props":253,"children":255},{"className":254},[],[256],{"type":59,"value":257},"--overwrite",{"type":59,"value":259}," (it destroys the\noriginal that consumers still import); write the fetched base variant\ncontent to ",{"type":53,"tag":68,"props":261,"children":263},{"className":262},[],[264],{"type":59,"value":265},"\u003Ccomponent>-base.tsx",{"type":59,"value":267}," instead.",{"type":53,"tag":96,"props":269,"children":270},{},[271,273,278,280,286],{"type":59,"value":272},"CUSTOMIZED wrappers: fetch the base variant and replay the user's diff\nonto it (their customizations must SURVIVE; ",{"type":53,"tag":68,"props":274,"children":276},{"className":275},[],[277],{"type":59,"value":257},{"type":59,"value":279}," would destroy\nthem). Mechanical implementation that works at scale:\n",{"type":53,"tag":68,"props":281,"children":283},{"className":282},[],[284],{"type":59,"value":285},"git merge-file user.tsx radix-golden.tsx base-golden.tsx",{"type":59,"value":287}," (three-way\nmerge, radix golden as ancestor) auto-resolves most files; hand-resolve\nconflicts with the reference tables.",{"type":53,"tag":96,"props":289,"children":290},{},[291,293,299,301,307],{"type":59,"value":292},"MANDATORY leftover sweep on EVERY golden-pair file, including ones that\nmerged \"clean\": ",{"type":53,"tag":68,"props":294,"children":296},{"className":295},[],[297],{"type":59,"value":298},"grep -n \"radix-ui\\|@radix-ui\\|IconPlaceholder\"",{"type":59,"value":300}," per\nfile. The registry sometimes reorders functions between variants, which\nmakes three-way merges report zero conflicts while leaving stale radix\nhunks in place. A clean merge is NOT proof of a clean file.\nThis is more reliable than reconstructing transforms; use it whenever the\npair exists. Consumer\u002Fapp code has no CLI mechanism: always hand-migrate it\nagainst ",{"type":53,"tag":68,"props":302,"children":304},{"className":303},[],[305],{"type":59,"value":306},"consumer-props.md",{"type":59,"value":308},".",{"type":53,"tag":96,"props":310,"children":311},{},[312,317,319,325],{"type":53,"tag":156,"props":313,"children":314},{},[315],{"type":59,"value":316},"Legacy styles (new-york, new-york-v4, default): classification only, no\nreplay.",{"type":59,"value":318}," These have no base counterpart (there is no base-new-york), and\nretargeting onto a base-",{"type":53,"tag":320,"props":321,"children":322},"style",{},[323],{"type":59,"value":324}," variant would restyle the user's app. Use\nthe radix golden ONLY to detect customizations, then run the transformation\nengine on the user's OWN file: rewire primitives, keep their exact classes,\napply class-mapping renames. Their look stays theirs. At the end of a\nlegacy whole-project migration, FLAG (do not fix): the style name still\nreads as radix to the CLI, so future shadcn add",{"type":59,"value":326}," will deliver radix\nvariants; the user decides whether to switch style or add manually.",{"type":53,"tag":96,"props":328,"children":329},{},[330,335,337,343,345,350,352,358,360,366,368,374,376,382,383,389,390,396,398,404,406,412],{"type":53,"tag":156,"props":331,"children":332},{},[333],{"type":59,"value":334},"Transformation engine (fallback).",{"type":59,"value":336}," Hand-rolled radix code, non-shadcn\nprojects, unknown styles: transform using ",{"type":53,"tag":68,"props":338,"children":340},{"className":339},[],[341],{"type":59,"value":342},"universal-patterns.md",{"type":59,"value":344}," (imports\nin BOTH forms: ",{"type":53,"tag":68,"props":346,"children":348},{"className":347},[],[349],{"type":59,"value":36},{"type":59,"value":351}," and ",{"type":53,"tag":68,"props":353,"children":355},{"className":354},[],[356],{"type":59,"value":357},"@radix-ui\u002Freact-*",{"type":59,"value":359},"; asChild->render with the\nworked example; Portal>Positioner>Popup; the positioner FORWARD rule; part\nrenames), the per-family props tables (",{"type":53,"tag":68,"props":361,"children":363},{"className":362},[],[364],{"type":59,"value":365},"overlays.md",{"type":59,"value":367},", ",{"type":53,"tag":68,"props":369,"children":371},{"className":370},[],[372],{"type":59,"value":373},"menus.md",{"type":59,"value":375},",\n",{"type":53,"tag":68,"props":377,"children":379},{"className":378},[],[380],{"type":59,"value":381},"form-controls.md",{"type":59,"value":367},{"type":53,"tag":68,"props":384,"children":386},{"className":385},[],[387],{"type":59,"value":388},"disclosure.md",{"type":59,"value":367},{"type":53,"tag":68,"props":391,"children":393},{"className":392},[],[394],{"type":59,"value":395},"display-misc.md",{"type":59,"value":397},"), ",{"type":53,"tag":68,"props":399,"children":401},{"className":400},[],[402],{"type":59,"value":403},"class-mapping.md",{"type":59,"value":405},"\nfor data-attribute\u002FCSS-var rewrites, and ",{"type":53,"tag":68,"props":407,"children":409},{"className":408},[],[410],{"type":59,"value":411},"wrapper-shapes.md",{"type":59,"value":413}," for exact\ntarget shapes (tooltip arrow, SubContent defaults, select anatomy).",{"type":53,"tag":85,"props":415,"children":417},{"id":416},"modes",[418],{"type":59,"value":419},"Modes",{"type":53,"tag":62,"props":421,"children":422},{},[423,428],{"type":53,"tag":156,"props":424,"children":425},{},[426],{"type":59,"value":427},"Progressive (default).",{"type":59,"value":429}," \"Migrate accordion\" = one component, strangler-fig:",{"type":53,"tag":92,"props":431,"children":432},{},[433,445,450],{"type":53,"tag":96,"props":434,"children":435},{},[436,438,443],{"type":59,"value":437},"Detect in-progress state first: an existing ",{"type":53,"tag":68,"props":439,"children":441},{"className":440},[],[442],{"type":59,"value":265},{"type":59,"value":444},",\nconsumers split between old\u002Fnew imports. The files ARE the state; resume,\nnever restart.",{"type":53,"tag":96,"props":446,"children":447},{},[448],{"type":59,"value":449},"If the component imports other ui wrappers still on radix (select ->\nbutton), STOP and recommend migrating those first, bottom-up.",{"type":53,"tag":96,"props":451,"children":452},{},[453,455,460,462,467,469,475,477,482,484,489],{"type":59,"value":454},"Write the migrated version to ",{"type":53,"tag":68,"props":456,"children":458},{"className":457},[],[459],{"type":59,"value":265},{"type":59,"value":461}," (original untouched;\ngolden-pair content fetched by URL, or transformed by hand, per the\nstrategy above); typecheck. Repoint consumers ONE AT A TIME (imports + the\ncall-site props in ",{"type":53,"tag":68,"props":463,"children":465},{"className":464},[],[466],{"type":59,"value":306},{"type":59,"value":468},"); typecheck each. When no consumer\nimports the original: delete it, rename ",{"type":53,"tag":68,"props":470,"children":472},{"className":471},[],[473],{"type":59,"value":474},"-base",{"type":59,"value":476}," -> original, flip imports\nback, final check, commit. When the LAST radix wrapper in the project is\nfinalized, flip ",{"type":53,"tag":68,"props":478,"children":480},{"className":479},[],[481],{"type":59,"value":205},{"type":59,"value":483}," to ",{"type":53,"tag":68,"props":485,"children":487},{"className":486},[],[488],{"type":59,"value":220},{"type":59,"value":490}," and remove radix deps.",{"type":53,"tag":62,"props":492,"children":493},{},[494,499,501,506],{"type":53,"tag":156,"props":495,"children":496},{},[497],{"type":59,"value":498},"Whole project",{"type":59,"value":500}," (only when explicitly asked): same per-component work in\ndependency order (leaf\u002Fshared wrappers like button and label first). After\nwrappers, sweep ALL app code against ",{"type":53,"tag":68,"props":502,"children":504},{"className":503},[],[505],{"type":59,"value":306},{"type":59,"value":507}," — the call-site\nbreak surface is much larger than asChild. Then remove radix deps, install,\nfull build.",{"type":53,"tag":85,"props":509,"children":511},{"id":510},"hard-rules",[512],{"type":59,"value":513},"Hard rules",{"type":53,"tag":149,"props":515,"children":516},{},[517,522,559,578,583],{"type":53,"tag":96,"props":518,"children":519},{},[520],{"type":59,"value":521},"NEVER touch non-radix libraries or their wrappers: cmdk (command), vaul\n(drawer), sonner, input-otp, react-day-picker (calendar), recharts (chart).\nReport them as intentionally untouched.",{"type":53,"tag":96,"props":523,"children":524},{},[525,527,533,535,541,543,549,551,557],{"type":59,"value":526},"No Base UI counterpart: AspectRatio -> CSS aspect-ratio div; Label ->\nnative ",{"type":53,"tag":68,"props":528,"children":530},{"className":529},[],[531],{"type":59,"value":532},"\u003Clabel>",{"type":59,"value":534},"; VisuallyHidden -> ",{"type":53,"tag":68,"props":536,"children":538},{"className":537},[],[539],{"type":59,"value":540},"sr-only",{"type":59,"value":542},"; Direction -> Direction\nProvider (",{"type":53,"tag":68,"props":544,"children":546},{"className":545},[],[547],{"type":59,"value":548},"direction",{"type":59,"value":550}," prop, not ",{"type":53,"tag":68,"props":552,"children":554},{"className":553},[],[555],{"type":59,"value":556},"dir",{"type":59,"value":558},"). Popover Anchor and NavigationMenu\nIndicator have no equivalent: inert passthrough + flag.",{"type":53,"tag":96,"props":560,"children":561},{},[562,568,570,576],{"type":53,"tag":68,"props":563,"children":565},{"className":564},[],[566],{"type":59,"value":567},"button.tsx",{"type":59,"value":569}," migrates to the REAL ",{"type":53,"tag":68,"props":571,"children":573},{"className":572},[],[574],{"type":59,"value":575},"@base-ui\u002Freact\u002Fbutton",{"type":59,"value":577}," primitive, never\na hand-rolled useRender wrapper.",{"type":53,"tag":96,"props":579,"children":580},{},[581],{"type":59,"value":582},"Behavior deltas are FLAGGED, never silently patched (tabs manual\nactivation, menu items not closing on click, nav-menu 50ms delay). The\ntarget is idiomatic Base UI matching the shadcn base registry.",{"type":53,"tag":96,"props":584,"children":585},{},[586],{"type":59,"value":587},"Honest reporting: skipped\u002Freverted files are listed as flagged, never as\nmigrated. Pre-existing failures are named as pre-existing.",{"type":53,"tag":85,"props":589,"children":591},{"id":590},"verify-and-report",[592],{"type":59,"value":593},"Verify and report",{"type":53,"tag":62,"props":595,"children":596},{},[597],{"type":59,"value":598},"Typecheck per file, build per batch, full build at the end vs the baseline.",{"type":53,"tag":62,"props":600,"children":601},{},[602,604,610,612,618,620,626],{"type":59,"value":603},"Reports live in a ",{"type":53,"tag":68,"props":605,"children":607},{"className":606},[],[608],{"type":59,"value":609},".migration\u002F",{"type":59,"value":611}," directory at the project root, ONE FILE PER\nCOMPONENT: ",{"type":53,"tag":68,"props":613,"children":615},{"className":614},[],[616],{"type":59,"value":617},".migration\u002F\u003Ccomponent>.md",{"type":59,"value":619}," (e.g. ",{"type":53,"tag":68,"props":621,"children":623},{"className":622},[],[624],{"type":59,"value":625},".migration\u002Faccordion.md",{"type":59,"value":627},").\nRules:",{"type":53,"tag":149,"props":629,"children":630},{},[631,636,641,654],{"type":53,"tag":96,"props":632,"children":633},{},[634],{"type":59,"value":635},"Each run writes (or fully overwrites) the file for each component it\nmigrated. Re-running a component replaces its report; never touch other\ncomponents' files.",{"type":53,"tag":96,"props":637,"children":638},{},[639],{"type":59,"value":640},"A multi-component run (\"migrate alert-dialog and dropdown-menu\") writes one\nfile per component, each self-contained; shared consumer-sweep notes are\nrepeated in every affected file.",{"type":53,"tag":96,"props":642,"children":643},{},[644,646,652],{"type":59,"value":645},"Whole-project mode writes the per-component files plus\n",{"type":53,"tag":68,"props":647,"children":649},{"className":648},[],[650],{"type":59,"value":651},".migration\u002Fproject.md",{"type":59,"value":653}," (dependency swap, app-code sweep summary, final\nbuild result).",{"type":53,"tag":96,"props":655,"children":656},{},[657,659,664],{"type":59,"value":658},"There is NO index file. Migration status is derived from disk, not\nmaintained: scan the project's ui directory (the ",{"type":53,"tag":68,"props":660,"children":662},{"className":661},[],[663],{"type":59,"value":40},{"type":59,"value":665}," alias from shadcn\ninfo, e.g. components\u002Fui or src\u002Fcomponents\u002Fui) for remaining radix imports\nwhen asked \"what's left\". End every run's summary with that derived count\n(\"N wrappers remain on Radix\").",{"type":53,"tag":62,"props":667,"children":668},{},[669,671,676],{"type":59,"value":670},"Each ",{"type":53,"tag":68,"props":672,"children":674},{"className":673},[],[675],{"type":59,"value":617},{"type":59,"value":677}," uses EXACTLY this structure (it is\ndocumented publicly; reports must match it):",{"type":53,"tag":679,"props":680,"children":685},"pre",{"className":681,"code":682,"language":683,"meta":684,"style":684},"language-md shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# \u003Ccomponent>\n\n\u003Cdate, strategy used (golden pair via CLI \u002F merge \u002F engine), one-line verdict>\n\n## Changed\n\n\u003Cevery file touched, with what changed and why; include file:line for\nanything notable. Confirm the leftover scan is clean:\ngrep -n \"radix-ui\\|@radix-ui\" on this component's files>\n\n## Left alone\n\n\u003Cfiles that look related but were intentionally not touched, with the reason\n(cmdk\u002Fvaul\u002Fsonner are not radix; unrelated drift; etc.)>\n\n## Behavior changes\n\n\u003Cdifferences that compile fine but act differently; flagged, never patched\n(tabs activation, menu close-on-click, delays...). Empty section if none>\n\n## Verify by hand\n\n\u003Cshort manual QA checklist for this primitive family: focus return on\ndialogs, keyboard nav + typeahead on menus\u002Fselect, tooltip delay feel,\nslider commit events. Concrete steps, one minute of clicking>\n","md","",[686],{"type":53,"tag":68,"props":687,"children":688},{"__ignoreMap":684},[689,706,716,726,734,748,756,765,774,783,791,804,812,821,830,838,851,859,868,877,885,898,906,915,924],{"type":53,"tag":188,"props":690,"children":693},{"class":691,"line":692},"line",1,[694,700],{"type":53,"tag":188,"props":695,"children":697},{"style":696},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[698],{"type":59,"value":699},"# ",{"type":53,"tag":188,"props":701,"children":703},{"style":702},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[704],{"type":59,"value":705},"\u003Ccomponent>\n",{"type":53,"tag":188,"props":707,"children":709},{"class":691,"line":708},2,[710],{"type":53,"tag":188,"props":711,"children":713},{"emptyLinePlaceholder":712},true,[714],{"type":59,"value":715},"\n",{"type":53,"tag":188,"props":717,"children":719},{"class":691,"line":718},3,[720],{"type":53,"tag":188,"props":721,"children":723},{"style":722},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[724],{"type":59,"value":725},"\u003Cdate, strategy used (golden pair via CLI \u002F merge \u002F engine), one-line verdict>\n",{"type":53,"tag":188,"props":727,"children":729},{"class":691,"line":728},4,[730],{"type":53,"tag":188,"props":731,"children":732},{"emptyLinePlaceholder":712},[733],{"type":59,"value":715},{"type":53,"tag":188,"props":735,"children":737},{"class":691,"line":736},5,[738,743],{"type":53,"tag":188,"props":739,"children":740},{"style":696},[741],{"type":59,"value":742},"## ",{"type":53,"tag":188,"props":744,"children":745},{"style":702},[746],{"type":59,"value":747},"Changed\n",{"type":53,"tag":188,"props":749,"children":751},{"class":691,"line":750},6,[752],{"type":53,"tag":188,"props":753,"children":754},{"emptyLinePlaceholder":712},[755],{"type":59,"value":715},{"type":53,"tag":188,"props":757,"children":759},{"class":691,"line":758},7,[760],{"type":53,"tag":188,"props":761,"children":762},{"style":722},[763],{"type":59,"value":764},"\u003Cevery file touched, with what changed and why; include file:line for\n",{"type":53,"tag":188,"props":766,"children":768},{"class":691,"line":767},8,[769],{"type":53,"tag":188,"props":770,"children":771},{"style":722},[772],{"type":59,"value":773},"anything notable. Confirm the leftover scan is clean:\n",{"type":53,"tag":188,"props":775,"children":777},{"class":691,"line":776},9,[778],{"type":53,"tag":188,"props":779,"children":780},{"style":722},[781],{"type":59,"value":782},"grep -n \"radix-ui\\|@radix-ui\" on this component's files>\n",{"type":53,"tag":188,"props":784,"children":786},{"class":691,"line":785},10,[787],{"type":53,"tag":188,"props":788,"children":789},{"emptyLinePlaceholder":712},[790],{"type":59,"value":715},{"type":53,"tag":188,"props":792,"children":794},{"class":691,"line":793},11,[795,799],{"type":53,"tag":188,"props":796,"children":797},{"style":696},[798],{"type":59,"value":742},{"type":53,"tag":188,"props":800,"children":801},{"style":702},[802],{"type":59,"value":803},"Left alone\n",{"type":53,"tag":188,"props":805,"children":807},{"class":691,"line":806},12,[808],{"type":53,"tag":188,"props":809,"children":810},{"emptyLinePlaceholder":712},[811],{"type":59,"value":715},{"type":53,"tag":188,"props":813,"children":815},{"class":691,"line":814},13,[816],{"type":53,"tag":188,"props":817,"children":818},{"style":722},[819],{"type":59,"value":820},"\u003Cfiles that look related but were intentionally not touched, with the reason\n",{"type":53,"tag":188,"props":822,"children":824},{"class":691,"line":823},14,[825],{"type":53,"tag":188,"props":826,"children":827},{"style":722},[828],{"type":59,"value":829},"(cmdk\u002Fvaul\u002Fsonner are not radix; unrelated drift; etc.)>\n",{"type":53,"tag":188,"props":831,"children":833},{"class":691,"line":832},15,[834],{"type":53,"tag":188,"props":835,"children":836},{"emptyLinePlaceholder":712},[837],{"type":59,"value":715},{"type":53,"tag":188,"props":839,"children":841},{"class":691,"line":840},16,[842,846],{"type":53,"tag":188,"props":843,"children":844},{"style":696},[845],{"type":59,"value":742},{"type":53,"tag":188,"props":847,"children":848},{"style":702},[849],{"type":59,"value":850},"Behavior changes\n",{"type":53,"tag":188,"props":852,"children":854},{"class":691,"line":853},17,[855],{"type":53,"tag":188,"props":856,"children":857},{"emptyLinePlaceholder":712},[858],{"type":59,"value":715},{"type":53,"tag":188,"props":860,"children":862},{"class":691,"line":861},18,[863],{"type":53,"tag":188,"props":864,"children":865},{"style":722},[866],{"type":59,"value":867},"\u003Cdifferences that compile fine but act differently; flagged, never patched\n",{"type":53,"tag":188,"props":869,"children":871},{"class":691,"line":870},19,[872],{"type":53,"tag":188,"props":873,"children":874},{"style":722},[875],{"type":59,"value":876},"(tabs activation, menu close-on-click, delays...). Empty section if none>\n",{"type":53,"tag":188,"props":878,"children":880},{"class":691,"line":879},20,[881],{"type":53,"tag":188,"props":882,"children":883},{"emptyLinePlaceholder":712},[884],{"type":59,"value":715},{"type":53,"tag":188,"props":886,"children":888},{"class":691,"line":887},21,[889,893],{"type":53,"tag":188,"props":890,"children":891},{"style":696},[892],{"type":59,"value":742},{"type":53,"tag":188,"props":894,"children":895},{"style":702},[896],{"type":59,"value":897},"Verify by hand\n",{"type":53,"tag":188,"props":899,"children":901},{"class":691,"line":900},22,[902],{"type":53,"tag":188,"props":903,"children":904},{"emptyLinePlaceholder":712},[905],{"type":59,"value":715},{"type":53,"tag":188,"props":907,"children":909},{"class":691,"line":908},23,[910],{"type":53,"tag":188,"props":911,"children":912},{"style":722},[913],{"type":59,"value":914},"\u003Cshort manual QA checklist for this primitive family: focus return on\n",{"type":53,"tag":188,"props":916,"children":918},{"class":691,"line":917},24,[919],{"type":53,"tag":188,"props":920,"children":921},{"style":722},[922],{"type":59,"value":923},"dialogs, keyboard nav + typeahead on menus\u002Fselect, tooltip delay feel,\n",{"type":53,"tag":188,"props":925,"children":927},{"class":691,"line":926},25,[928],{"type":53,"tag":188,"props":929,"children":930},{"style":722},[931],{"type":59,"value":932},"slider commit events. Concrete steps, one minute of clicking>\n",{"type":53,"tag":320,"props":934,"children":935},{},[936],{"type":59,"value":937},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":939,"total":708},[940,948],{"slug":4,"name":4,"fn":5,"description":6,"org":941,"tags":942,"stars":26,"repoUrl":27,"updatedAt":28},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[943,944,945,946,947],{"name":24,"slug":25,"type":15},{"name":17,"slug":18,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"name":21,"slug":22,"type":15},{"slug":37,"name":37,"fn":949,"description":950,"org":951,"tags":952,"stars":26,"repoUrl":27,"updatedAt":957},"manage shadcn\u002Fui components and projects","Manages shadcn components and projects — adding, searching, fixing, debugging, styling, and composing UI, including chat interfaces. Provides project context, component docs, and usage examples. Applies when working with shadcn\u002Fui, component registries, presets, --preset codes, or any project with a components.json file. Also triggers for \"shadcn init\", \"create an app with --preset\", or \"switch to --preset\".",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[953,954,955,956],{"name":24,"slug":25,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"name":21,"slug":22,"type":15},"2026-07-26T05:50:08.026115",{"items":959,"total":708},[960,968],{"slug":4,"name":4,"fn":5,"description":6,"org":961,"tags":962,"stars":26,"repoUrl":27,"updatedAt":28},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[963,964,965,966,967],{"name":24,"slug":25,"type":15},{"name":17,"slug":18,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"name":21,"slug":22,"type":15},{"slug":37,"name":37,"fn":949,"description":950,"org":969,"tags":970,"stars":26,"repoUrl":27,"updatedAt":957},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[971,972,973,974],{"name":24,"slug":25,"type":15},{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"name":21,"slug":22,"type":15}]