Radix ist am Ende, nutzt stattdessen das hier... (Base UI)

BBetter Stack
Computing/SoftwareInternet Technology

Transcript

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

Key Takeaway

Base UI positioniert sich als modernere, aktiv gepflegte und funktionsreichere Headless-Alternative zu Radix UI, die eine bessere Performance und flexiblere Entwickler-Erfahrung bietet.

Highlights

Base UI wird von den ursprünglichen Machern von Radix

Timeline

Einführung in Base UI und das Problem mit Radix

Der Sprecher empfiehlt Entwicklern, von Radix-Komponenten zu Base UI zu wechseln, besonders wenn sie bereits shadcn nutzen. Base UI ist eine Headless-UI-Bibliothek, die von den Experten hinter Radix, Floating UI und Material UI ins Leben gerufen wurde. Sie konzentriert sich auf Barrierefreiheit und Funktionalität, während das Design vollständig dem Entwickler überlassen bleibt. Dies ist laut Video entscheidend, da KI-Modelle bei komplexen Accessibility-Anforderungen oft noch an ihre Grenzen stoßen. Die Dokumentation wird als vorbildlich gelobt, da sie Beispiele für CSS-Module und Tailwind bietet.

Wartung und der "Zombie-Zustand" von Radix

Ein entscheidender Unterschied liegt in der aktiven Pflege der Repositories auf GitHub. Während Base UI stetig wächst und zahlreiche Issues sowie Pull Requests schließt, weist Radix kaum noch Aktivitäten auf. Der Sprecher erklärt dies mit der Übernahme durch WorkOS, nach der viele Kern-Entwickler das Team verlassen haben. Sogar ein Mitbegründer von Radix empfiehlt die Library nur noch als letzte Option und arbeitet nun selbst an Base UI. Für Entwickler bedeutet dieser Wechsel vor allem Sicherheit vor ungelösten Bugs und langfristige Wartbarkeit ihrer Projekte.

Die neue Render-Prop vs. asChild

Technisch gesehen verbessert Base UI das bekannte "asChild"-Konzept von Radix durch die Einführung einer dedizierten "render"-Prop. Diese macht den Code expliziter und vermeidet das versehentliche Übersehen von Props beim schnellen Scannen des Quellcodes. Die "render"-Prop erlaubt es zudem, Funktionen zu übergeben, um auf den internen Zustand der Komponente zuzugreifen. So kann beispielsweise ein Switch-Thumb je nach Aktivierungsstatus unterschiedliche Icons rendern. Diese Flexibilität wird als großer Vorteil für individuelle Anpassungen und fortgeschrittene Logik hervorgehoben.

Datengesteuertes Rendering und Performance

Base UI ermöglicht es, Komponenten wie Select-Felder direkt über Daten-Arrays zu steuern. Im Vergleich zu Radix, wo man manuell über Arrays mappen muss, kennt die Base UI Komponente die Daten durch eine "items"-Prop bereits vor dem Rendering. Dies führt zu einer spürbar besseren Performance, was insbesondere im Kontext von Server-Side Rendering (SSR) relevant ist. Der Sprecher sieht hier jedoch noch weiteres Optimierungspotenzial, indem man sich am Ansatz von React Aria orientiert. Dennoch stellt dies bereits jetzt eine strukturelle Verbesserung gegenüber dem alten Radix-Modell dar.

Exklusive Features: Multi-Select und Combo-Box

Ein großer Kritikpunkt an Radix war oft das Fehlen komplexerer Komponenten wie eines Multi-Selects oder einer Combo-Box. Base UI schließt diese Lücken und bietet eine einfache "multiple"-Prop für Select-Komponenten an. Zusätzlich stehen Werkzeuge für Autocomplete zur Verfügung, die in modernen Webanwendungen fast unverzichtbar sind. Da die Library aktiv gepflegt wird, können die Entwickler zeitnah auf solche Community-Wünsche reagieren. Dies macht Base UI zu einer attraktiven Wahl für Projekte, die über Standard-Eingabefelder hinausgehen.

Fortgeschrittenes Styling und Fazit

Abschließend wird die Styling-Flexibilität gelobt, die es erlaubt, Klassennamen basierend auf dem Zustand der Komponente als Funktion zu definieren. Dies verhindert extrem lange Tailwind-Klassen-Strings und harmoniert exzellent mit Bibliotheken wie Tailwind Variants. Base UI wird als die "goldene Mitte" zwischen der Einfachheit von Radix und der Komplexität von React Aria bezeichnet. Der Sprecher empfiehlt Base UI für alle neuen Projekte und sieht eine Migration bestehender Apps als sinnvoll an, sobald spezifische neue Features benötigt werden. Er weist darauf hin, dass die Library auch Features wie Input-Scrubbing und verschachtelte Dialoge hervorragend unterstützt.

Community Posts

View all posts