For teams moving a shadcn project off Radix UI
Base UI Deskradix-ui imports, Content, asChild, data-[state=open]. The mechanical changes happen right here; the hand-off items get a review.
Paste one Radix UI file - a shadcn ui wrapper, a page that uses the wrappers, or a hand-rolled composition. Your browser rewrites the mechanical layer: both import forms become one @base-ui/react subpath, Overlay becomes Backdrop, a popover or menu Content becomes Portal > Positioner > Popup with side and align on the Positioner, asChild becomes render, and data-[state=open] becomes data-open. It flags what needs a hand: the animation idiom, dismiss callbacks, the parts Base UI lacks and the behavior changes - and it never touches cmdk, vaul or sonner. Then the review, and the whole file.
The source file free
The scan free
What the scan found
The skill's migration layers
The Base UI copy free
What the page changed itself - the imports, the part renames, Portal > Positioner > Popup, asChild to render, Part.Props, the data-state classes and --radix variables, and the 1:1 call-site props - saved as <component>-base.tsx next to the original, the way the skill's progressive migration works. Everything that needs a decision is left as it was.
component-base.tsx
The review metered
Pricing as soon as the session is ready...
Sign inThe reply could not be read. Here it is as it came back:
Caveats
Caveats
The page's check of this reply
Saved reviews
How it works - and what it cannot see
The scan reads the JSX itself: comments, strings, template literals and regex literals are masked, every element is matched to its closing tag, and the migration runs as passes that each make small edits that never overlap, with every finding kept on its pasted line. A class is read in the tag it sits on, so data-[state=open] becomes data-popup-open on a trigger, data-panel-open on an accordion trigger and data-open on the popup. A nested asChild (a tooltip trigger around a dialog trigger) is resolved innermost first.
It cannot see a handler that used the Radix event argument, a positioning prop spread through ...props, or how a delay should feel - that is the review, which also writes the behavior changes and the hand checks for the .migration report. The page re-scans the rewritten file, so a Radix part left behind is flagged rather than trusted, and every component keeps its name.