Transcript

00:00:00Arrêtez d'utiliser les composants Radix et passez à autre chose : Base UI. D'ailleurs, si vous êtes fan de shadcn,
00:00:06il est déjà possible de faire la transition. Si vous n'avez jamais entendu parler de Base UI,
00:00:10sachez que c'est une bibliothèque UI "headless" créée par les auteurs originaux de Radix, Floating UI et Material UI.
00:00:15Elle apporte les fonctionnalités et l'accessibilité des composants, tout en vous laissant la main sur le design,
00:00:20ce qui est crucial aujourd'hui, car les LLM ont encore du mal avec les cas particuliers et l'accessibilité. Mais ce que je
00:00:24viens de décrire, c'est exactement la définition de Radix.
00:00:30Alors pourquoi en changer ? Voyons ça tout de suite avec les principales différences.
00:00:35Je vais d'abord vous montrer rapidement la documentation de Base UI pour que vous voyiez tous les
00:00:44composants disponibles sur la gauche. Ils proposent quasiment tout ce dont vous auriez besoin
00:00:48dans votre bibliothèque, et même des composants avancés comme le "Combo Box"
00:00:52qui n'existe pas dans Radix. Pour chacun, vous avez un bel exemple de mise en œuvre et de
00:00:57personnalisation avec des modules CSS ou même Tailwind si vous préférez.
00:01:01La doc est excellente, mais on n'est pas là pour comparer la documentation. Passons à la première
00:01:06différence majeure, celle dont vous entendrez le plus parler :
00:01:10Base UI est activement maintenu, alors que Radix est un peu à l'état de zombie. Si l'on regarde
00:01:15les graphiques de contribution sur GitHub, on voit que Base UI ne cesse de croître, tandis que Radix
00:01:20ne reçoit que de rares commits sporadiques. C'est encore plus flagrant si l'on regarde
00:01:25les PR et les tickets fermés le mois dernier : Base UI a résolu 58 problèmes et
00:01:29fusionné 154 pull requests, contre zéro pour Radix. Pour résumer l'histoire,
00:01:36WorkOS a racheté l'entreprise derrière Radix mais n'a pas vraiment investi dedans.
00:01:42L'équipe de Radix est donc partie en grande partie, et nous voilà dans cette situation. Le co-créateur
00:01:47de Radix a même déclaré qu'il ne l'utiliserait qu'en dernier recours... et il travaille désormais
00:01:53sur Base UI. Il s'agit donc de s'assurer que vos applications dépendent de projets actifs pour éviter
00:01:58des maux de tête futurs face à des bugs qui ne seront jamais corrigés. Mieux encore,
00:02:02Base UI a été conçu pour ressembler à Radix, donc la migration ne devrait pas être trop pénible.
00:02:08Cela ne les empêche pas de glisser quelques améliorations, et l'une de mes préférées
00:02:13concerne la gestion de la propriété "asChild" que l'on trouve dans Radix. Si vous ne connaissez pas,
00:02:17j'ai ici un composant Select de Radix. Pour rendre un composant personnalisé
00:02:22en tant que déclencheur (trigger), si je l'entoure simplement avec le composant "Select.Trigger",
00:02:27j'obtiens un composant conteneur en plus du bouton "S'abonner" (cliquez dessus d'ailleurs !).
00:02:31Mais si je veux que le bouton serve directement de déclencheur,
00:02:36je dois ajouter la propriété "asChild" sur le déclencheur. Cela dit à
00:02:41Radix de fusionner toutes les propriétés et fonctionnalités du déclencheur avec son composant enfant.
00:02:46On le voit ici : le nom de la classe est fusionné avec le bouton et prend même le dessus.
00:02:50Si je retire cette propriété et que je sauvegarde, on a bien un bouton, mais il
00:02:55fait maintenant office de déclencheur pour mon Select.
00:03:00C'est une fonctionnalité pratique, mais on lui reprochait souvent son manque de clarté.
00:03:04J'avoue qu'en parcourant du code rapidement, il m'arrivait de rater cette propriété et
00:03:09de ne pas comprendre d'où venait un problème. Voyons comment Base UI gère cela :
00:03:13on obtient le même résultat — un bouton qui sert de déclencheur —
00:03:18mais si vous regardez le code, Base UI utilise la propriété "render" au lieu de "asChild".
00:03:24Avec la propriété "render", vous spécifiez directement le composant que vous voulez afficher
00:03:29comme déclencheur. C'est un changement mineur, mais je trouve cela beaucoup plus
00:03:34explicite. On voit littéralement ce qui est rendu. Pas besoin de vérifier
00:03:39s'il y a un composant enfant ou de chercher la propriété "asChild".
00:03:43C'est un petit détail, mais très pertinent. Et ce n'est pas tout le potentiel de la propriété "render".
00:03:48Ici, sur un composant Switch, on peut passer une fonction à la propriété "render".
00:03:52Cela permet d'accéder aux propriétés et à l'état du composant que l'on
00:03:56construit, comme ici pour le curseur (thumb). Cela nous permet de choisir sur quel composant
00:04:01appliquer les propriétés transmises, mais aussi d'ajouter une logique de rendu
00:04:05ou de style personnalisée basée sur l'état. Avec ce curseur de switch,
00:04:10on peut savoir s'il est coché, modifié, désactivé, rempli, etc. Dans ce cas,
00:04:14on vérifie simplement s'il est coché pour afficher
00:04:18une icône différente. Il existe même un hook pour intégrer cette propriété "render"
00:04:22dans vos propres composants personnalisés. On rentre dans le complexe, mais vous voyez
00:04:27que Base UI peut tout gérer. Revenons à mon composant Select :
00:04:31l'autre différence est que Base UI permet une approche basée sur les données.
00:04:35On peut le voir ici avec le Select. Voici d'abord le code Radix :
00:04:40nous avons un tableau avec nos libellés et valeurs, et pour les injecter dans le
00:04:44Select, on doit itérer (map) sur le tableau "apples" et
00:04:49rendre un composant "SelectItem" pour chaque valeur. Voyons maintenant
00:04:54comment Base UI procède. C'est très similaire : on a toujours notre tableau
00:04:59et on itère toujours dessus pour rendre les éléments, mais on l'inclut
00:05:03aussi à un autre endroit : sur le composant racine "Select.Root".
00:05:08On lui passe le tableau, ce qui a un impact subtil : le composant
00:05:13connaît les données avant même le rendu. Cela améliore légèrement les performances,
00:05:17surtout pour le rendu côté serveur (SSR). Je pense toutefois qu'on pourrait
00:05:22améliorer un point : là, je passe "apples" dans la propriété "items",
00:05:26mais j'itère aussi dessus plus bas. On l'utilise donc à deux endroits.
00:05:32Je préférerais l'approche de React Aria, une autre bibliothèque headless. Regardez :
00:05:36on passe le tableau "animals" aux "items", puis pour les
00:05:41enfants, on utilise simplement une fonction. Celle-ci connaît déjà tous les éléments
00:05:45transmis au parent. On n'utilise pas le tableau deux fois et l'élément parent
00:05:50sert de fournisseur de données. C'est un point qui pourrait encore être peaufiné.
00:05:55Mais revenons à notre Select pour une autre différence, cette fois spécifique
00:05:59à ce composant. Si la propriété "render" et l'approche par données
00:06:03se retrouvent partout, cette fonctionnalité-ci est propre au Select :
00:06:08la sélection multiple. C'était cruellement absent de Radix.
00:06:13Dans Base UI, il suffit d'ajouter la propriété "multiple" (true ou false) sur la racine du Select
00:06:17pour qu'il devienne multi-sélection. C'est aussi simple que ça. Et pour
00:06:22aller plus loin, Base UI propose des composants absents de Radix comme le "Combo Box"
00:06:27ou l'Auto-complétion. C'est l'avantage d'une maintenance active qui répond aux demandes.
00:06:33Il reste deux différences que je veux vous montrer entre Radix et Base UI.
00:06:38On va passer au composant Checkbox parce que je commence à me lasser
00:06:41du Select. La première concerne le style. Base UI offre
00:06:45une option de stylisation vraiment cool. Ici, j'utilise Tailwind.
00:06:50On peut utiliser les approches classiques (CSS normal, modules CSS, etc.),
00:06:55mais avec Tailwind, on style généralement un composant
00:06:59en utilisant des attributs de données pour l'état. Par exemple, avec "data-checked",
00:07:04on applique une couleur de fond. On se retrouve vite avec une très longue chaîne
00:07:08de caractères dans Tailwind, ce qui peut devenir problématique.
00:07:13Base UI permet donc d'utiliser une fonction pour définir le nom de la classe (className).
00:07:17Cela donne accès à l'état du composant. Pour cette case à cocher,
00:07:22j'applique des styles selon qu'elle est cochée ou désactivée via une simple condition.
00:07:26Je trouve que c'est plus lisible : on voit d'un coup d'œil
00:07:31d'où viennent les styles d'état, au lieu de devoir scanner
00:07:35une ligne interminable à la recherche des attributs "data". C'est encore
00:07:40plus utile si vous utilisez Vanilla CSS. Ça fonctionne aussi
00:07:45très bien avec une bibliothèque que j'adore : Tailwind Variants. Regardez,
00:07:49je passe l'état à ma fonction checkbox, et dans ma variante Tailwind,
00:07:53on a nos styles de base, puis nos variantes. Je peux dire : "si checked est vrai,
00:07:58applique ces styles ; si disabled est vrai, applique ceux-là".
00:08:02C'est parfois bien plus clair que les attributs de données, mais c'est une affaire de goût.
00:08:06C'est génial que Base UI nous laisse le choix. J'ajoute que j'avais
00:08:11adoré cette utilisation de fonction pour les classes dans React Aria.
00:08:14Pour moi, on a d'un côté React Aria, très puissant mais avec une courbe d'apprentissage raide,
00:08:19et de l'autre Radix, assez simple. Base UI se situe pile au milieu, prenant le
00:08:23meilleur des deux pour créer la bibliothèque headless ultime. Voilà pour les
00:08:28principales différences, mais il y en a d'autres : Base UI supporte très bien
00:08:33React Hook Form et TanStack Form, facilite les animations des composants
00:08:38et propose même des fonctions comme le réglage numérique par glissement (input scrubbing),
00:08:42les dialogues imbriqués ou les menus au survol. Et comme le projet est actif,
00:08:47ils répondront sûrement à vos suggestions sur GitHub. Cela dit,
00:08:52je ne migrerais pas forcément une application Radix existante tout de suite,
00:08:57car Radix n'est pas totalement hors service. Mais pour un nouveau projet, je choisirais Base UI,
00:09:02ou si j'avais besoin d'un Combo Box ou d'une auto-complétion. Dites-moi
00:09:07ce que vous en pensez en commentaire, abonnez-vous et, comme toujours,
00:09:11à la prochaine !

Key Takeaway

Base UI s'impose comme le successeur spirituel et technique de Radix UI, offrant une maintenance active, une meilleure ergonomie de développement et des fonctionnalités avancées indispensables pour les projets modernes.

Highlights

Base UI est développée par les créateurs originaux de Radix

Timeline

Introduction et présentation de Base UI

L'auteur présente Base UI comme l'alternative incontournable aux composants Radix pour les développeurs utilisant shadcn ou des bibliothèques "headless". Cette nouvelle bibliothèque est conçue par les experts à l'origine de Material UI et Floating UI, garantissant une expertise solide en accessibilité. L'intérêt majeur réside dans le contrôle total du design, un point devenu crucial à l'ère des outils de génération par IA. La documentation est déjà très complète, proposant des exemples concrets avec CSS Modules ou Tailwind CSS. Cette introduction pose les bases d'une comparaison nécessaire face à l'essoufflement de Radix.

Le déclin de Radix vs la montée de Base UI

Cette section analyse la santé des deux projets via leurs statistiques sur GitHub. L'auteur souligne que Radix est devenu un projet stagnant, qualifié de "zombie", suite à son rachat par WorkOS et au départ de son équipe initiale. En contraste, Base UI affiche une activité intense avec des centaines de pull requests et de corrections de bugs fusionnées chaque mois. Le co-créateur de Radix lui-même recommande désormais d'utiliser Base UI en priorité. Il est donc risqué pour une application moderne de dépendre d'une bibliothèque qui ne corrige plus ses failles. La migration est toutefois facilitée car Base UI a été pensé pour ressembler à son prédécesseur.

L'évolution de la propriété asChild vers render

L'auteur explore une amélioration syntaxique majeure : le passage de la propriété "asChild" de Radix à la propriété "render" de Base UI. Bien que pratique, "asChild" manquait souvent de clarté lors de la lecture rapide du code, provoquant des erreurs de compréhension. Base UI rend le rendu explicite en permettant de passer directement le composant souhaité ou même une fonction. Cette fonction donne accès à l'état interne du composant, comme l'état "coché" ou "désactivé" d'un switch. Cela permet d'injecter une logique visuelle dynamique, comme le changement d'icônes, sans alourdir le code. Un hook dédié permet même d'intégrer cette puissance dans des composants personnalisés créés par l'utilisateur.

Gestion des données et sélection multiple

Le comparatif se poursuit sur la gestion des listes de données, où Base UI adopte une approche plus performante pour le SSR. Contrairement à Radix qui nécessite une itération manuelle uniquement dans le rendu, Base UI permet de passer les données directement à la racine du composant. L'auteur mentionne au passage React Aria comme une référence qui va encore plus loin dans cette logique de fournisseur de données. Un avantage décisif est également mis en avant : le support natif de la sélection multiple dans les menus déroulants. Cette fonctionnalité, réclamée depuis longtemps par la communauté Radix, est enfin disponible de série. Base UI comble ainsi des lacunes historiques tout en simplifiant le code final.

Stylisation dynamique et conclusion

La dernière partie traite de l'intégration avec Tailwind CSS et des bibliothèques de variantes. Base UI permet d'utiliser des fonctions pour définir les classes CSS, évitant ainsi les longues chaînes d'attributs "data-" difficiles à maintenir. Cette méthode rend le code beaucoup plus lisible en isolant la logique de style liée à l'état (checked, disabled, etc.). L'auteur positionne Base UI comme le compromis parfait entre la simplicité de Radix et la complexité technique de React Aria. Des fonctionnalités avancées comme le support de React Hook Form ou les menus au survol sont également mentionnées. En conclusion, bien qu'une migration immédiate ne soit pas obligatoire pour les projets stables, Base UI devient le choix par défaut pour tout nouveau développement.

Community Posts

View all posts