I migrated shadcn from Radix to Base UI (nobody asked me to)

This weekend, I moved shadcn from Radix UI to Base UI on pretty much all my projects. Nothing was breaking, everything worked, and the perf gain doesn't exist.
In short, a migration nobody recommends. I did it anyway. Here's why.
In 2023 it's Radix or nothing
When shadcn/ui showed up in January 2023, it was built on Radix.
Headless components, accessible, clean APIs, battle-tested on millions of apps... shadcn didn't really choose Radix, it was just the only serious foundation around.
You copied unstyled primitives, slapped Tailwind on top, and it worked. For two years, no reason to even ask the question.
The same devs, but two years later
Then the same people who built Radix (Colm Tuite chief among them), plus the guy behind Floating UI and the MUI team, went off to build Base UI.
It's not a competitor trying to kill Radix: it's the same team doing the job a second time, with two years of lessons in their pockets. Their v1 ships in late 2025, stable, with 35 components.
Base UI by default
The detail that changes everything: since July 2026, Base UI is the default in shadcn. You scaffold a new project, it comes up on Base UI, not Radix anymore.
What changes (spoiler: not perf)
The point is somewhere other than benchmarks. It's literal, you can see it in the code. Three examples.
Radix's asChild becomes a render prop. Less magic hidden in a Slot, you see exactly what you're rendering:
// Radix
<Dialog.Trigger asChild>
<Button>Ouvrir</Button>
</Dialog.Trigger>
// Base UI
<Dialog.Trigger render={<Button>Ouvrir</Button>} />
Popup positioning is no longer driven by props on Content, but by an explicit Positioner that wraps the Popup:
// Radix
<DropdownMenu.Content side="left" align="start">…</DropdownMenu.Content>
// Base UI
<DropdownMenu.Positioner side="left" align="start">
<DropdownMenu.Popup>…</DropdownMenu.Popup>
</DropdownMenu.Positioner>And on the dependencies side, no more constellation of @radix-ui/react-*: a single native package.
# Radix
npm i @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-popover
# Base UI
npm i @base-ui/reactMore verbose in places, sure. But more honest about what's actually happening. Bonus: Base UI ships primitives Radix never had — multiple Select, Combobox, Autocomplete, Drawer.
The real reason: the checkbox
Let's be honest: everything above is after-the-fact rationalization.
The real reason is psychological. There's that category of people who, in a game, can't put the controller down until the bar hits 100%, every trophy unlocked, every box ticked. They're called completionists. I'm one of them.
And "recommended, available, stable, official default" is exactly the kind of box I can't leave unticked. It's not tech debt I'm paying down, it's a 100% I'm unlocking.
Do we migrate or not?
shadcn says it himself: the worst thing you can do to a production app is switch component libraries. He's right. You don't have to migrate — Radix is still mature, tested, supported, and nothing rots if you don't move.
So the reasonable advice:
stable app in production → don't touch a thing
living projects, templates, side-projects → migrate while it's painless and the API gap is still small
either way, there's an official migration skill (Claude Code, Cursor) that works component by component, one commit each, rollback = you delete the branch. Count on 20 minutes.
Anyway, do whatever you want. But for me, the box is ticked.
Comments (0)
> No comments yet.