shadcn/ui est passé à Base UI. Voici ce qui change vraiment dans votre code
shadcn/ui utilise désormais Base UI par défaut au lieu de Radix. Chaque changement d’API que vous rencontrerez, la porte de sortie -b radix et un ordre de migration qui ne fait pas mal.
Preet Suthar · · 5 min de lecture
- React
- shadcn/ui
- Base UI
- Radix
Le 3 juillet 2026, npx shadcn init a commencé à choisir Base UI au lieu de Radix. Si vous avez lu les gros titres et rien d’autre, vous pensez probablement l’une de ces deux choses : que Radix est mort, ou que rien n’a changé. Aucune des deux n’est vraie.
Je maintiens HextaUI, un registre shadcn/ui construit sur Base UI, j’ai donc passé l’essentiel de l’année dans les deux couches de primitives. Voici le guide que j’aurais voulu avoir en juillet : ce qui a changé, ce qui n’a pas changé, chaque différence d’API que vous rencontrerez, et l’ordre dans lequel migrer si vous vous y décidez.
Ce qui a changé, en un paragraphe
Les nouveaux projets shadcn/ui reçoivent des primitives Base UI. Radix reste entièrement pris en charge. L’équipe shadcn a indiqué que chaque mise à jour et chaque nouveau composant sortent pour les deux bibliothèques, sauf si un composant n’existe que dans Base UI. Les projets existants ne sont pas touchés. Si vous voulez Radix sur un projet neuf, vous passez un flag :
Si vous avez une CI ou des scripts qui appellent init de façon non interactive et attendent Radix, ajoutez ce flag dès maintenant, avant qu’un checkout tout frais ne vous surprenne.
Pourquoi le défaut a changé
Deux raisons ont été données. Base UI avait atteint une version stable 1.6.0 avec plus de six millions de téléchargements hebdomadaires, et les projets créés via shadcn/create choisissaient déjà Base UI plutôt que Radix à environ deux contre un. Le défaut a suivi ce que les gens choisissaient.
Base UI est construit par les personnes derrière Radix, Material UI et Floating UI, et la filiation se voit. Il couvre des primitives que Radix n’a jamais publiées, comme Combobox, Autocomplete, Number Field, Toast et Preview Card. En septembre 2026, il en est à la version 1.8.0.
Faut-il migrer une application existante ?
Probablement pas ce trimestre, et pas d’un seul coup.
Restez sur Radix si l’application est stable, que vous n’êtes pas bloqué par une primitive manquante et que personne dans l’équipe n’a de reproche précis. Rien de ce dont vous dépendez ne disparaît.
Migrez si vous avez besoin de Combobox ou de Number Field sans sortir une seconde bibliothèque, si vous réécrivez déjà les composants pour Tailwind v4 de toute façon, ou si vous voulez être sur la couche que les nouveaux composants shadcn/ui ciblent en premier.
Dans les deux cas, lisez la section suivante avant de décider, parce que les différences ne sont pas cosmétiques.
Chaque différence d’API que vous rencontrerez vraiment
Je les ai regroupés selon la façon dont ils échouent. Le premier groupe casse votre build. Le second compile très bien et change le comportement silencieusement, ce qui est pire.
Les changements qui cassent le build
asChild devient render. C’est celui que tout le monde rencontre en premier.
La prop render accepte un élément ou une fonction. La forme fonction vous donne l’état, ce qui est utile pour des choses comme un déclencheur qui change d’icône une fois ouvert.
Les popups ancrés gagnent un Positioner. Menu, Select, Popover et Tooltip passent de Portal > Content à Portal > Positioner > Popup. Dialog n’a pas de Positioner ; il utilise Backdrop et Popup.
Overlay s’appelle maintenant Backdrop. Renommez et passez à la suite.
Les valeurs de Select sont nullables. Un Select contrôlé contient Value | null, pas string. Votre useState<string>("") devient useState<string | null>(null), et chaque endroit qui lisait la valeur comme une chaîne a besoin d’une garde.
Les valeurs d’Accordion et de Toggle Group sont toujours des tableaux. Même en mode simple, value="a" devient value={["a"]}. Tabs garde une valeur unique.
onOpenChange a un second argument. Radix vous laisse appeler event.preventDefault() pour empêcher une fermeture. Base UI passe (open, details) et vous appelez details.cancel(). Le champ details.reason vous dit si c’était la touche Échap, un clic à l’extérieur ou autre chose, ce qui est pratique pour les dialogues « modifications non enregistrées ».
Les sélecteurs d’état ouvert changent. Les variantes data-[state=open]: deviennent data-open:. Celui-ci se cache dans vos chaînes className et dans vos variantes cva, alors faites un grep sur data-[state= avant de déclarer la migration terminée.
Les changements de comportement silencieux
Tabs s’active manuellement par défaut. Dans Radix, les flèches déplacent le focus et activent l’onglet. Dans Base UI, les flèches déplacent le focus et vous appuyez sur Entrée ou Espace pour activer. Si vos tests ou vos utilisateurs attendent le comportement de Radix, définissez activateOnFocus sur la liste.
Les items de menu checkbox et radio gardent le menu ouvert. closeOnClick vaut false par défaut pour CheckboxItem et RadioItem. Les items simples ferment toujours. C’est sans doute le meilleur défaut, mais c’est un changement que vos utilisateurs remarqueront.
Les menus de navigation s’ouvrent plus vite. Le delay au survol de Base UI vaut 50 ms par défaut. Le delayDuration de Radix valait 200 ms par défaut. Les menus rapides sont agréables jusqu’à ce que quelqu’un balaie l’en-tête avec sa souris et que trois panneaux s’ouvrent à la suite. Ajustez-le.
Un ordre de migration qui ne fait pas mal
Gardez les deux bibliothèques installées. Migrez un composant par commit. Lancez vos tests entre chaque. Dans cet ordre :
- Les composants feuilles sans popup : Switch, Checkbox, Slider, Toggle, Progress. Surtout du renommage.
- Tabs et Accordion. Corrigez les valeurs en tableau et tranchez sur
activateOnFocus. - Dialog et Alert Dialog. Apprenez ici la structure
BackdropetPopupet le patterndetails.cancel(), là où aucun Positioner ne vient brouiller les pistes. - Popover et Tooltip. Ajoutez le
Positioner. - Select, Combobox, Dropdown Menu, Context Menu. Valeurs nullables,
closeOnClicket tout l’arbre de popup. Faites-les en dernier, avec le plus de tests.
Remplacer un composant par sa version Base UI tient en une commande CLI, et votre source est dans git, alors relisez le diff plutôt que de lui faire confiance :
Puis git diff components/ui/dialog.tsx, et lisez chaque ligne avant de le garder.
Ce que je ne ferais pas
Je ne lancerais pas un codemod sur tout l’arbre en croisant les doigts. Les changements qui cassent le build sont faciles à trouver. Les silencieux ne le sont pas, et un codemod ne peut pas vous dire que votre page de réglages demande maintenant deux frappes pour changer d’onglet.
Je ne changerais pas non plus de couche de primitives et ne redessinerais pas les composants dans la même PR. L’intérêt de shadcn/ui, c’est que vous possédez le code. Le posséder, c’est lire le diff.
Si vous voulez que la migration soit faite pour vous
HextaUI est un registre que vous ajoutez à un projet shadcn/ui. Chaque composant est déjà écrit sur Base UI, garde les noms et les props de shadcn/ui, et utilise les mêmes tokens de thème, donc npx shadcn@latest add https://hextaui.com/r/dialog.json --overwrite dépose un Dialog Base UI dans components/ui à côté de vos autres fichiers. Les composants sont MIT et gratuits. La page HextaUI vs shadcn/ui liste ce qui diffère et quand shadcn/ui seul est le meilleur choix.
FAQ
Radix est-il déprécié ? Non. shadcn/ui publie chaque composant pour les deux bibliothèques, et l’équipe fait toujours tourner Radix en production.
Puis-je mélanger des composants Radix et Base UI dans un même projet ? Oui. Vous portez les deux dépendances pendant la migration. Beaucoup de projets resteront mixtes longtemps, et ce n’est pas un problème.
Dois-je changer mes tokens de thème ? Non. --background, --primary, --radius et les autres sont inchangés. La couche de primitives est indépendante du côté Tailwind.
Base UI prend-il en charge les React Server Components ? Les primitives Base UI sont des composants client, comme Radix. Gardez la directive "use client" là où shadcn/ui la place.
Où est le journal des modifications officiel ? L’entrée de juillet 2026 est sur ui.shadcn.com/docs/changelog/2026-07-base-ui-default.