J'ai migré shadcn de Radix vers Base UI (personne me l'a demandé)

Ce week-end, j'ai passé shadcn de Radix UI à Base UI sur à peu près tous mes projets. Rien ne cassait, tout tournait, et le gain de perf n'existe pas.
Bref, une migration que personne ne recommande. Je l'ai faite quand même. Voilà pourquoi.
En 2023 c'est Radix ou rien
Quand shadcn/ui débarque en janvier 2023, il est bâti sur Radix.
Des composants headless, accessibles, des APIs propres, éprouvés sur des millions d'apps, ... shadcn n'a pas vraiment choisi Radix, c'était juste le seul socle sérieux du marché.
Tu copiais des primitives non stylées, tu collais du Tailwind par-dessus, ça marchait. Pendant deux ans, aucune raison de se poser la question.
Les mêmes dev mais deux ans après
Puis les mêmes gens qui ont fait Radix (Colm Tuite en tête), plus le type derrière Floating UI et l'équipe de MUI, sont partis construire Base UI.
Ce n'est pas un concurrent qui veut tuer Radix : c'est la même équipe qui refait le boulot une deuxième fois, avec deux ans de leçons dans les poches. Leur v1 sort fin 2025, stable, avec 35 composants.
Base UI par défaut
Le détail qui change tout : depuis juillet 2026, Base UI est le défaut dans shadcn. Tu scaffoldes un nouveau projet, il part sur Base UI, plus sur Radix.
Ce qui change (spoiler : pas la perf)
L'intérêt est ailleurs que dans les benchmarks. C'est littéral, ça se voit dans le code. Trois exemples.
Le asChild de Radix devient un render prop. Moins de magie planquée dans un Slot, tu vois ce que tu rends :
// Radix
<Dialog.Trigger asChild>
<Button>Ouvrir</Button>
</Dialog.Trigger>
// Base UI
<Dialog.Trigger render={<Button>Ouvrir</Button>} />
Le positionnement des popups ne se pilote plus par des props posées sur le Content, mais par un Positioner explicite qui enveloppe le Popup :
// Radix
<DropdownMenu.Content side="left" align="start">…</DropdownMenu.Content>
// Base UI
<DropdownMenu.Positioner side="left" align="start">
<DropdownMenu.Popup>…</DropdownMenu.Popup>
</DropdownMenu.Positioner>Et côté dépendances, fini la constellation de @radix-ui/react-* : un seul package natif.
# Radix
npm i @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-popover
# Base UI
npm i @base-ui/reactPlus verbeux par endroits, oui. Mais plus honnête sur ce qui se passe vraiment. Bonus : Base UI embarque des primitives que Radix n'a jamais eues — Select multiple, Combobox, Autocomplete, Drawer.
Le vrai argument : la case à cocher
Soyons honnêtes : tout ce qui précède, c'est de la rationalisation a posteriori.
La vraie raison est psychologique. Il y a cette catégorie de gens qui, dans un jeu, ne peuvent pas lâcher la manette tant que la barre n'est pas à 100 %, tous les trophées débloqués, toutes les cases cochées. On appelle ça des complétionnistes. J'en suis.
Et « recommandé, disponible, stable, défaut officiel », c'est exactement le genre de case que je ne peux pas laisser décochée. Ce n'est pas de la dette technique que je rembourse, c'est un 100 % que je débloque.
On migre ou pas ?
shadcn le dit lui-même : le pire truc que tu puisses faire à une app en prod, c'est changer de lib de composants. Il a raison. Tu n'as pas à migrer — Radix reste mûr, testé, supporté, et rien ne pourrit si tu ne bouges pas.
Donc le conseil raisonnable :
projet stable en prod → touche à rien
projets vivants, templates, side-projects → migre tant que c'est indolore et que l'écart d'API est encore petit
dans tous les cas, il existe un skill de migration officiel (Claude Code, Cursor) qui bosse composant par composant, un commit chacun, rollback = tu supprimes la branche. Compte 20 minutes.
Enfin, tu fais comme tu veux hein. Mais pour moi la case est cochée.
Commentaires (0)
> Aucun commentaire pour l'instant.