00:00:00Hört auf, Radix-Komponenten zu benutzen, und wechselt zu – tja, Base UI. Wenn ihr shadcn-Fans seid,
00:00:06gibt es dort bereits die Option umzusteigen. Falls ihr noch nie von Base UI gehört habt: Es stammt
00:00:10tatsächlich von den ursprünglichen Machern von Radix, Floating UI und Material UI. Es ist eine Headless-UI-Library,
00:00:15sie liefert also die Funktionalität und Barrierefreiheit der Komponenten, während ihr das Design bestimmt.
00:00:20Das ist heutzutage besonders wichtig, da LLMs bei all diesen Sonderfällen und Accessibility-Anforderungen noch nicht perfekt sind.
00:00:24Aber was ich da beschreibe, ist im Grunde genau das, was auch Radix ist.
00:00:30Warum braucht man also eine neue Library? Schauen wir direkt rein und ich zeige euch die Hauptunterschiede.
00:00:35Ich beginne kurz mit der Base UI-Dokumentation, damit ihr all die
00:00:44verfügbaren Komponenten sehen könnt. Hier links sieht man fast alles, was man
00:00:48für eine eigene Komponenten-Bibliothek braucht – sogar Fortgeschrittenes wie die Combo-Box hier,
00:00:52die es bei Radix nicht gibt. Zu jeder Komponente gibt es ein schönes Beispiel, wie man sie einsetzt
00:00:57und mit CSS-Modulen stylt. Man kann das Beispiel auf Wunsch sogar auf Tailwind umstellen.
00:01:01Die Dokumentation ist wirklich gut, aber wir sind nicht hier, um Dokumentationen zu vergleichen.
00:01:06Kommen wir zum ersten entscheidenden Unterschied, den man wahrscheinlich am häufigsten hört:
00:01:10Base UI wird aktiv gepflegt, während Radix in einer Art „Zombie-Zustand“ verharrt. Wenn wir uns
00:01:15die GitHub-Contribution-Charts ansehen, sieht man, dass Base UI stetig wächst. Bei Radix gibt es
00:01:20nur gelegentlich mal einen Commit. Noch deutlicher wird es, wenn man die geschlossenen Issues
00:01:25und PRs des letzten Monats betrachtet: Base UI hat 58 Issues geschlossen und
00:01:29154 Pull Requests gemergt, während Radix gar nichts vorzuweisen hat. Die Kurzfassung zu Radix:
00:01:36WorkOS hat die Firma hinter Radix gekauft, aber nicht wirklich investiert. Das Team ist daraufhin
00:01:42größtenteils gegangen, was uns zum heutigen Zustand führt. Sogar der Mitbegründer von Radix sagte,
00:01:47er würde Radix nur noch als letzte Option nutzen – und ja, er arbeitet jetzt an Base UI.
00:01:53Es geht also darum, sicherzustellen, dass eure Apps und Abhängigkeiten aktiv gewartet werden
00:01:58und euch in Zukunft keine Kopfschmerzen bereiten, falls ihr auf einen Bug stoßt, der nicht behoben wird.
00:02:02Das Beste ist: Base UI ist Radix sehr ähnlich, eine Migration sollte also nicht allzu schwer sein.
00:02:08Das heißt aber nicht, dass sie nicht ein paar Verbesserungen eingebaut haben. Eine meiner liebsten
00:02:13ist die Handhabung der „asChild“-Prop, die man von Radix kennt. Falls ihr das nicht kennt:
00:02:17Ich habe hier ein Radix-Select. Wenn ich eine eigene Komponente als Select-Trigger rendern möchte,
00:02:22würde ich sie normalerweise einfach mit der Select-Trigger-Komponente umschließen. Dann hätte ich aber
00:02:27sowohl eine Wrapper-Komponente als auch den Button mit dem Text „Abonnieren“ (den ihr übrigens anklicken solltet).
00:02:31Wenn ich aber möchte, dass der Abonnieren-Button selbst direkt als Select-Trigger fungiert,
00:02:36muss ich in Radix nur die „asChild“-Prop zum Trigger hinzufügen. Das sagt Radix,
00:02:41dass alle Props und Funktionen dieses Select-Triggers mit der untergeordneten Komponente zusammengeführt werden sollen.
00:02:46Man sieht das daran, dass der Klassenname hier mit dem des Buttons verschmilzt und ihn überschreibt.
00:02:50Wenn ich die Prop lösche und speichere, haben wir zwar einen Button, aber funktional dient er jetzt
00:02:55als mein Select-Trigger. Das ist eine ziemlich praktische Funktion.
00:03:00Ein häufiger Kritikpunkt war jedoch, dass es nicht sehr explizit ist. Ich gebe zu,
00:03:04beim schnellen Überfliegen von Code habe ich diese Prop manchmal übersehen und die Ursache eines Problems nicht gefunden.
00:03:09Schauen wir uns an, wie Base UI das macht. Man bekommt die exakt gleiche Funktionalität:
00:03:13Ich habe hier einen Button, der als Select-Trigger dient. Aber im Code benutzt Base UI
00:03:18statt „asChild“ die „render“-Prop. In dieser „render“-Prop gibt man dann die Komponente an,
00:03:24die als Select-Trigger gerendert werden soll. Das ist eine winzige Änderung, aber ich finde,
00:03:29es macht viel deutlicher, was hier passiert: Es wird buchstäblich diese Komponente gerendert.
00:03:34Man muss nicht erst prüfen, ob eine Child-Komponente genutzt wird oder nach der „asChild“-Prop suchen.
00:03:39Wie gesagt, eine kleine, aber meiner Meinung nach sehr gute Änderung. Und das ist noch nicht alles,
00:03:43was die „render“-Prop kann. Wenn wir einen Switch bauen, können wir der „render“-Prop
00:03:48sogar eine Funktion übergeben. So können wir auf die Props und den Zustand der Komponente zugreifen,
00:03:52die wir gerade erstellen – in diesem Fall der „Switch Thumb“. Das erlaubt uns erstens zu wählen,
00:03:56auf welche Komponente wir die Props anwenden wollen, und zweitens eine eigene Logik für das Rendering
00:04:01oder das Styling basierend auf dem Zustand zu implementieren. Beim Switch-Thumb können wir prüfen,
00:04:05ob er „checked“, „dirty“, „disabled“ oder vieles mehr ist. Hier prüfen wir einfach,
00:04:10ob er aktiviert ist, und rendern in diesem Fall ein anderes Icon. Es gibt sogar einen Hook,
00:04:14mit dem man diese „render“-Prop-Logik in eigene Komponenten einbauen kann. Aber das wird jetzt
00:04:18etwas zu fortgeschritten. Man sieht jedenfalls: Alles, was man individuell anpassen will, lässt sich mit Base UI lösen.
00:04:22Zurück zu meiner Select-Komponente. Der nächste Unterschied ist, dass Base UI es erlaubt,
00:04:27bestimmte Komponenten datengesteuert zu füllen. Das sehen wir hier am Beispiel des Selects.
00:04:31Hier ist der aktuelle Radix-Select-Code: Wir haben ein Array mit Labels und Werten.
00:04:35Um die Werte in das Select zu bekommen, müssen wir in Radix einfach über das „apples“-Array mappen
00:04:40und jeweils ein „SelectItem“ rendern, um die Werte so einzufügen. Wenn wir uns nun ansehen,
00:04:44wie Base UI das macht, ist es sehr ähnlich. Wir haben immer noch unser Array mit Label und Wert
00:04:49und wir mappen auch hier darüber, um ein „SelectItem“ zu rendern. Aber wir geben das Array
00:04:54zusätzlich auch hier oben bei „SelectRoute“ an. Das hat einen subtilen Effekt:
00:04:59Die Komponente kennt die zu rendernden Daten schon vor dem Rendering-Vorgang.
00:05:03Das sorgt für eine etwas bessere Performance, besonders beim Server-Side Rendering. Eine Sache,
00:05:08die man hierbei aber noch verbessern könnte: Aktuell übergebe ich „apples“ als „items“-Prop,
00:05:13mappe dann aber weiter unten erneut über das gleiche Array. Wir nutzen es also an zwei Stellen.
00:05:17Besser wäre es, wie React Aria (eine andere Headless-Library) es macht. Dort haben wir unser Array,
00:05:22übergeben es hier als „items“ und nutzen für die Children einfach eine Funktion.
00:05:26Diese kennt dann alle Items, die dem Parent-Element übergeben wurden. So nutzt man das Array
00:05:32nicht an zwei Stellen und der Parent fungiert als Data-Provider. Da gibt es also noch Optimierungspotenzial.
00:05:36Zurück zum Select – ich möchte euch einen weiteren Unterschied zeigen, der spezifisch für diese Komponente ist.
00:05:41Während die „render“-Prop und der datengesteuerte Ansatz fast überall verfügbar sind, ist dieses Feature
00:05:45exklusiv für das Select: Man kann ein Multi-Select erstellen. Das hat man bei Radix schmerzlich vermisst.
00:05:50In Base UI muss man nur die Prop „multiple“ (true oder false) zum Select-Root hinzufügen,
00:05:55und schon hat man ein Multi-Select. So einfach ist das. Um noch einen draufzusetzen:
00:05:59Base UI bietet weitere Komponenten, die bei Radix fehlen, wie eine Combo-Box oder Autocomplete.
00:06:03Das ist eben der Vorteil aktiver Wartung: Man kann auf User-Wünsche reagieren.
00:06:08Zwei weitere Unterschiede zwischen Radix und Base UI möchte ich euch noch zeigen. Wir wechseln
00:06:13dafür zur Checkbox-Komponente, weil mir das Select langsam zu langweilig wird.
00:06:17Der erste Punkt betrifft das Styling. Base UI bietet hier eine weitere Option, die ich echt cool finde.
00:06:22Aktuell benutze ich Tailwind. Man kann natürlich alle klassischen Ansätze wie CSS oder CSS-Module nutzen.
00:06:27Wenn man Tailwind nutzt, stylt man solche Komponenten typischerweise über Daten-Attribute für den Zustand,
00:06:33also etwa „data-checked“. Wenn das aktiv ist, nutzen wir eine Primärfarbe für den Hintergrund.
00:06:38Das führt oft zu sehr langen Strings in Tailwind, was unübersichtlich werden kann. Eine Option bei
00:06:41Base UI ist daher die Nutzung einer Funktion als Klassenname. Diese gibt Zugriff auf den Zustand.
00:06:45Bei der Checkbox wende ich Styles an, je nachdem, ob sie aktiviert oder deaktiviert ist.
00:06:50Das mache ich mit einer einfachen Bedingung. Ich finde, man sieht so auf einen Blick,
00:06:55woher die Styles für „checked“ oder „disabled“ kommen, statt eine lange Zeile nach Daten-Attributen absuchen zu müssen.
00:06:59Besonders hilfreich ist das, wenn man Vanilla-CSS nutzt. Es harmoniert auch super mit einer
00:07:04anderen Library, die ich sehr mag: Tailwind Variants. Hier übergebe ich einfach den Zustand
00:07:08an meine Checkbox-Funktion. Oben in der Tailwind-Variante haben wir unsere Basis-Styles,
00:07:13aber auch unsere Varianten. Ich sage einfach: Wenn „checked“ wahr ist, nimm diese Styles,
00:07:17wenn „disabled“ wahr ist, nimm jene. Manchmal ist das viel klarer als Daten-Attribute,
00:07:22aber das ist natürlich Geschmackssache. Es ist einfach toll, dass Base UI uns die Wahl lässt.
00:07:26Ich muss auch sagen, dass ich mich zuerst bei React Aria in die Nutzung von Funktionen für Klassennamen verliebt habe.
00:07:31Es wirkt auf mich so: Wir haben React Aria auf der einen Seite, das eine steile Lernkurve hat,
00:07:35und Radix auf der anderen, das recht simpel ist. Base UI trifft genau die goldene Mitte,
00:07:40vereint die besten Features beider Welten und ist für mich die ultimative Headless-Library.
00:07:45Das waren die wichtigsten Unterschiede für dieses Video, aber es gibt noch viel mehr: Base UI bietet
00:07:49super Support für React Hook Form und TanStack Form. Es unterstützt Animationen, um diesen Prozess
00:07:53zu vereinfachen, und bietet Features wie Input-Scrubbing, verschachtelte Dialoge oder Hover-Menüs.
00:07:58Und da es aktiv gepflegt wird, bin ich sicher, dass sie auf GitHub auch auf eure Anfragen reagieren.
00:08:02Allerdings würde ich jetzt nicht sofort jede Radix-App auf Base UI migrieren, denn Radix
00:08:06ist ja nicht völlig kaputt. Bei einem neuen Projekt würde ich definitiv Base UI wählen,
00:08:11und wenn ich Features wie eine Combo-Box oder Autocomplete brauche, würde ich eine Migration in Erwägung ziehen.
00:08:14Schreibt mir eure Meinung zu Base UI in die Kommentare, abonniert den Kanal und wie immer:
00:08:19Wir sehen uns im nächsten Video!
00:08:23features that i like about both of them and created me the ultimate headless library now that's all of
00:08:28the key differences that i wanted to go over in this video but there is still loads more like base ui has
00:08:33great support for react hook form and tan stack form it has animation support to make it a nice
00:08:38and easy process to actually animate your components and it even has features like input scrubbing
00:08:42nested dialogues and triggering menus on hover and i'm sure if you have a reasonable request they'd
00:08:47actually respond to it over on the github as it is actively maintained it is also worth saying though
00:08:52that i probably wouldn't jump to migrating my radix app over to base ui straight away as i don't think
00:08:57radix is completely broken if i'm starting a new project i definitely use base ui now and if i wanted
00:09:02a feature like a combo box or an autocomplete i'd also consider migrating my application let me know
00:09:07what you think of base ui in the comments though while you're down there subscribe and as always
00:09:11see you in the next one