React UI-Komponentenbibliotheken im Vergleich: shadcn/ui, Radix, Headless UI, daisyUI, Flowbite und MUI

shadcn/ui, Radix, Headless UI, daisyUI, Flowbite und MUI unterscheiden sich vor allem im Styling: Radix und Headless UI sind ungestylt, daisyUI und Flowbite sind vorgestyltes Tailwind, MUI ist Material Design, und shadcn/ui kopiert gestylten Code in dein Projekt. Hier sind dieselben sechs Komponenten in jeder Bibliothek, plus eine Empfehlung, welche du wählen solltest.

Die Kurzfassung

Diese sechs Bibliotheken lösen unterschiedliche Probleme, deshalb gibt es auf die Frage nach der besten keine einzelne Antwort. Zwei davon (Radix Primitives und Headless UI) liefern Verhalten und Barrierefreiheit ohne Styling. Zwei (daisyUI und Flowbite) liefern einen fertigen Tailwind-Look. MUI liefert ein komplettes Designsystem mit eigener Styling-Engine. shadcn/ui ist überhaupt kein Paket: Es kopiert gestylten Komponenten-Quellcode in dein Projekt, aufgebaut auf einer Headless-Schicht darunter.

Alle Fakten unten (Versionen, Lizenzen, Voraussetzungen) wurden im Oktober 2026 mit der offiziellen Dokumentation, dem GitHub-Repository und dem npm-Eintrag jedes Projekts abgeglichen. Versionen ändern sich schnell, betrachte die Zahlen also als Stand zum Zeitpunkt des Schreibens.

Vergleichstabelle

shadcn/uiRadix PrimitivesHeadless UIdaisyUIFlowbite ReactMUI (Material UI)
Was du installiersteine CLI, die Komponenten-Quellcode in dein Repo kopiertnpm-Pakete (radix-ui oder eines pro Komponente)@headlessui/reactdaisyui Tailwind-Pluginflowbite-react@mui/material plus Emotion
Styling-ModellTailwind-Klassen in Code, der dir gehört; Theme über CSS-Variablenungestylt; du ergänzt Klassen, Zustand über data-state-Attributeungestylt; Zustand über data-*-Attribute, für Tailwind konzipiertCSS-Komponentenklassen (btn, modal) und Themesvorgestylte Tailwind-Komponenten, anpassbar per ThemeMaterial Design, CSS-in-JS (sx-Prop, Theme-Objekt)
Version (Okt. 2026)CLI shadcn 4.x (kein Laufzeitpaket)radix-ui 1.8; einzelne Pakete 1.x und 2.x2.25.x0.12 (vor 1.0)9.x
LizenzMITMITMITMITMITMIT (kostenpflichtiges MUI X Pro/Premium ist separat)
React erforderlichja16.8 bis 1918 oder 19nein (reines HTML und CSS)18 oder 1917, 18 oder 19
Tailwind erforderlichja (v4 in der aktuellen Doku)neinnein, aber dafür gedachtja, Tailwind 4 für daisyUI 5ja, Tailwind 3 oder 4nein
Ansatz zur Barrierefreiheitübernimmt sie von seiner Primitive-Schicht (Base UI oder Radix)folgt den WAI-ARIA Authoring Practices; Tastatur und Fokus eingebautbeschrieben als „vollständig barrierefrei“; Tastatur und Fokus eingebautsetzt auf native Elemente (<dialog>, <details>); ARIA und Verhalten ergänzt du selbstReact-Komponenten mit Positionierung über Floating UI; Tastaturbedienung selbst testenARIA und Tastatursteuerung pro Komponente, pro Komponente dokumentiert
Hat einen Toastja, über Sonnerja (Toast)neinja (nur Layout-Klasse)ja (Toast)ja (Snackbar)

Die Bundle-Größe haben wir bewusst aus der Tabelle weggelassen. Die Zahlen hängen stark davon ab, welche Komponenten du importierst, ob dein Bundler sie per Tree-Shaking entfernt und (bei daisyUI) wie viel CSS Tailwind für die genutzten Klassen erzeugt. Eine einzelne „kB“-Zahl pro Bibliothek würde mehr verwirren als helfen. Miss deinen eigenen Build: Lass den Analyzer deines Bundlers vor und nach dem Hinzufügen der Komponenten laufen, die du wirklich brauchst.

Jede Bibliothek im Detail

shadcn/ui

Was es ist. shadcn/ui beschreibt sich selbst als „keine Komponentenbibliothek“, sondern als „die Art, wie du deine Komponentenbibliothek baust“. Du führst seine CLI aus (npx shadcn init, dann npx shadcn add button), und sie schreibt den Komponenten-Quellcode in dein Projekt. Ab dann gehört der Code dir und du kannst ihn bearbeiten; es gibt kein shadcn-Laufzeitpaket, das aktualisiert werden muss.

Styling. Tailwind-CSS-Klassen in den kopierten Dateien, mit Farben und Radien als CSS-Variablen, sodass du das Theme an einer Stelle ändern kannst. Varianten werden meist mit class-variance-authority definiert.

Unter der Haube. Die interaktiven Teile sitzen auf einer Headless-Bibliothek. Laut dem Changelog von shadcn/ui nutzen neue Projekte seit Juli 2026 standardmäßig Base UI, und Radix „wird nicht abgekündigt“: Beide werden unterstützt. Der Toast basiert auf Sonner, einem separaten Open-Source-Toast-Paket.

Lizenz und Version. MIT (GitHub-Repository shadcn-ui/ui). Das CLI-Paket shadcn stand zum Zeitpunkt des Schreibens auf npm bei 4.x.

Achte auf. Weil dir der Code gehört, gehört dir auch die Pflege. Korrekturen im Original erreichen deine Kopien nicht automatisch, und verschiedene Projekte entwickeln sich mit der Zeit auseinander.

Radix Primitives

Was es ist. Eine Sammlung ungestylter, barrierefreier React-Komponenten (Dialog, Dropdown-Menü, Tabs, Switch, Toast, Tooltip, Popover und mehr). Du kannst alles aus dem einzelnen Paket radix-ui installieren (zum Zeitpunkt des Schreibens 1.8) oder ein Paket pro Komponente, etwa @radix-ui/react-dialog.

Styling. Standardmäßig keines. Jedes Teil rendert ein einfaches Element, das du mit jeder Methode stylen kannst. Der Zustand wird als Data-Attribut bereitgestellt, zum Beispiel data-state="open" oder data-highlighted, was gut zu Tailwinds Varianten data-[state=open]: passt.

Barrierefreiheit. Laut der Radix-Dokumentation folgen die Primitives den WAI-ARIA Authoring Practices, bieten Tastaturunterstützung und verwalten den Fokus (zum Beispiel halten sie den Fokus in einem geöffneten Dialog und geben ihn beim Schließen zurück).

Lizenz und Voraussetzungen. MIT. Der Bereich der npm-Peer-Dependency deckt React 16.8 bis 19 ab.

Achte auf. Du schreibst jeden Style selbst. Radix liefert kein Button-Primitive: Nutze ein natives <button> oder das Hilfsmittel Slot, um Props in dein eigenes Element zu übernehmen.

Headless UI

Was es ist. Ungestylte Komponenten vom Tailwind-CSS-Team. Das React-Paket @headlessui/react (zum Zeitpunkt des Schreibens 2.2) enthält Button, Checkbox, Combobox, Dialog, Disclosure, Fieldset, Input, Listbox, Menu (Dropdown), Popover, Radio Group, Select, Switch, Tabs, Textarea und Transition.

Styling. Ungestylt. Komponenten stellen ihren Zustand über Data-Attribute bereit (data-open, data-checked, data-selected, data-focus), sodass du sie mit Tailwind-Varianten wie data-checked:bg-blue-600 (Syntax von Tailwind 4) oder data-[checked]:bg-blue-600 (Tailwind 3) stylst.

Barrierefreiheit. Die Website beschreibt die Komponenten als „komplett ungestylt, vollständig barrierefrei“. Tastaturnavigation, Fokusfalle in Dialogen und ARIA-Verknüpfungen sind eingebaut.

Lizenz und Voraussetzungen. MIT. React 18 oder 19 (npm-Peer-Dependency).

Achte auf. Die Sammlung ist kleiner als bei Radix: Es gibt keinen Toast, keinen Tooltip und keinen Slider, dafür brauchst du ein weiteres Paket.

daisyUI

Was es ist. Ein Tailwind-CSS-Plugin, das Komponenten-Klassennamen wie btn, modal, dropdown, tabs, toggle und toast sowie eine Reihe von Farbthemes hinzufügt. Es liefert CSS, keine React-Komponenten, und funktioniert daher mit jedem Framework oder auch ganz ohne.

Styling. Semantische Klassen mit Modifikatoren (btn btn-primary btn-sm), die du weiterhin mit normalen Tailwind-Utilities kombinieren kannst. Themes wechseln über CSS-Variablen.

Voraussetzungen. daisyUI 5 (erstmals im Februar 2025 veröffentlicht, zum Zeitpunkt des Schreibens 5.x) zielt auf Tailwind CSS 4; laut Upgrade-Leitfaden aktualisierst du zuerst Tailwind. Du installierst es mit einer einzigen Zeile @plugin "daisyui"; in deinem CSS.

Barrierefreiheit. Da es nur CSS ist, kommt das Verhalten aus nativem HTML: Das Modal nutzt das <dialog>-Element (Escape schließt es, und der Browser kümmert sich um den Fokus), Dropdowns nutzen <details> oder die Popover API. Alles darüber hinaus (ARIA für Tabs, Ansagen von Toasts) ist deine Aufgabe.

Lizenz. MIT.

Achte auf. In React verdrahtest du den Zustand selbst (zum Beispiel rufst du showModal() über eine Ref auf). Pfeiltasten-Steuerung für Menüs oder Tabs gibt es nur, wenn du sie ergänzt.

Flowbite React

Was es ist. React-Komponenten (flowbite-react), mit Tailwind gestylt, aus dem Flowbite-Projekt. Enthalten sind Button, Modal, Dropdown, Tabs, ToggleSwitch, Toast, Navbar, Sidebar, Datepicker und mehr.

Styling. Mit Tailwind-Klassen vorgestylt, anpassbar über ein Theme-Objekt und eine theme-Prop an jeder Komponente.

Voraussetzungen und Version. Zum Zeitpunkt des Schreibens Version 0.12: Es hat 1.0 noch nicht erreicht, rechne also mit Breaking Changes zwischen Minor-Versionen. Die npm-Peer-Dependencies sind React 18 oder 19 und Tailwind CSS 3 oder 4. Für die Positionierung von Dropdowns und Tooltips wird Floating UI genutzt.

Barrierefreiheit. Die Komponenten rendern die erwarteten Rollen für gängige Muster, aber wir haben keine veröffentlichte Erklärung zur Barrierefreiheit gefunden, die mit der von Radix vergleichbar wäre. Teste Tastatur- und Screenreader-Verhalten für die Komponenten, auf die du dich verlässt.

Lizenz. MIT (die Open-Source-Bibliothek; Flowbite verkauft außerdem separate Pro-Blöcke und Designdateien).

MUI (Material UI)

Was es ist. In eigenen Worten „eine Open-Source-React-Komponentenbibliothek, die Googles Material Design umsetzt“. Es ist die größte Sammlung in diesem Vergleich, mit Komponenten für Datenanzeige, Eingaben, Navigation, Layout und Feedback.

Styling. CSS-in-JS. Standardmäßig wird Emotion genutzt (@emotion/react und @emotion/styled sind Peer-Dependencies von @mui/material 9). Das Theme legst du mit createTheme fest, Einzelfälle stylst du mit der sx-Prop. Es kann neben Tailwind laufen, aber die beiden Theme-Systeme teilen keine Tokens, solange du sie nicht verbindest.

Version und Lizenz. Version 9 (9.0.0 erschien im April 2026). Die Kernbibliothek steht unter MIT. Erweiterte Funktionen für Datentabellen, Datum und Diagramme in MUI X Pro und Premium sind kommerzielle Lizenzen.

Barrierefreiheit. Komponenten kommen mit ARIA-Attributen und Tastatursteuerung, und die Komponentenseiten in der MUI-Doku beschreiben das Verhalten zur Barrierefreiheit pro Komponente.

Achte auf. Sich vom Material-Look zu lösen, erfordert echte Arbeit am Theme, und CSS-in-JS braucht mit React Server Components zusätzliche Einrichtung.

Dieselben sechs Komponenten in jeder Bibliothek

Unten sind derselbe Button, Dialog, dasselbe Dropdown-Menü, dieselben Tabs, derselbe Switch und derselbe Toast sechsmal geschrieben, jeweils mit der dokumentierten API der Bibliothek. Jedes Snippet ist eigener, für diese Seite geschriebener Code (nicht aus den Dokus der Bibliotheken kopiert), nutzt die aktuelle Hauptversion jeder Bibliothek und ist auf die Teile gekürzt, die sich unterscheiden. Live und anklickbar zeigen wir nur Radix Primitives, weil Radix die Bibliothek ist, die auf dieser Website installiert ist. Sie sind mit unseren eigenen Tailwind-Klassen gestylt, da Radix keine Styles mitliefert. Von den anderen fünf Bibliotheken zeigen wir keine Live-Versionen, damit hier nichts ihren Look nachahmt.

Button

Die meisten Bibliotheken liefern einen Button mit Varianten. Achte darauf, wie Radix und Headless UI den Look dir überlassen, während daisyUI Varianten als Klassen ausdrückt und die übrigen als Props.

Button: shadcn/ui

// after: npx shadcn add button
import { Button } from "@/components/ui/button";

<Button>Save changes</Button>
<Button variant="outline" size="sm">Cancel</Button>
<Button variant="destructive" disabled>Delete</Button>
<Button asChild><a href="/pricing">See pricing</a></Button>

Button: Radix Primitives

// Radix has no Button primitive. Use a native button,
// or Slot to pass props onto your own element.
import { Slot } from "radix-ui";

function Button({ asChild, className, ...props }) {
  const Comp = asChild ? Slot.Root : "button";
  return <Comp className={"rounded-lg bg-black px-4 py-2 text-white " + className} {...props} />;
}

Button: Headless UI

import { Button } from "@headlessui/react";

<Button className="rounded-lg bg-black px-4 py-2 text-white
  data-hover:bg-black/80 data-active:bg-black/70
  data-disabled:opacity-50">
  Save changes
</Button>

Button: daisyUI

<button className="btn btn-primary">Save changes</button>
<button className="btn btn-outline btn-sm">Cancel</button>
<button className="btn btn-error" disabled>Delete</button>
<a className="btn btn-link" href="/pricing">See pricing</a>

Button: Flowbite React

import { Button } from "flowbite-react";

<Button>Save changes</Button>
<Button color="alternative" size="sm">Cancel</Button>
<Button color="red" disabled>Delete</Button>
<Button href="/pricing">See pricing</Button>

Button: MUI

import Button from "@mui/material/Button";

<Button variant="contained">Save changes</Button>
<Button variant="outlined" size="small">Cancel</Button>
<Button variant="contained" color="error" disabled>Delete</Button>
<Button href="/pricing">See pricing</Button>

Dialog (Modal)

Im Dialog steckt die versteckte Arbeit für Barrierefreiheit: Fokusfalle, Schließen mit Escape, Rückgabe des Fokus an den Auslöser, Beschriftung. Die Headless-Bibliotheken und MUI erledigen das in JavaScript; daisyUI stützt sich auf das native <dialog>-Element, das Escape und Fokus im Browser regelt.

Dialog (Modal): shadcn/ui

import {
  Dialog, DialogContent, DialogDescription, DialogFooter,
  DialogHeader, DialogTitle, DialogTrigger, DialogClose,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";

<Dialog>
  <DialogTrigger asChild><Button>Edit profile</Button></DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Edit profile</DialogTitle>
      <DialogDescription>Update your display name.</DialogDescription>
    </DialogHeader>
    {/* form fields */}
    <DialogFooter>
      <DialogClose asChild><Button variant="outline">Cancel</Button></DialogClose>
      <Button type="submit">Save</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

Dialog (Modal): Radix Primitives

import { Dialog } from "radix-ui";

<Dialog.Root>
  <Dialog.Trigger className="btn-dark">Edit profile</Dialog.Trigger>
  <Dialog.Portal>
    <Dialog.Overlay className="fixed inset-0 bg-black/40" />
    <Dialog.Content className="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-xl bg-white p-5">
      <Dialog.Title>Edit profile</Dialog.Title>
      <Dialog.Description>Update your display name.</Dialog.Description>
      {/* form fields */}
      <Dialog.Close>Cancel</Dialog.Close>
    </Dialog.Content>
  </Dialog.Portal>
</Dialog.Root>

Dialog (Modal): Headless UI

import { Dialog, DialogPanel, DialogTitle, DialogBackdrop } from "@headlessui/react";
import { useState } from "react";

const [open, setOpen] = useState(false);

<button onClick={() => setOpen(true)}>Edit profile</button>
<Dialog open={open} onClose={setOpen} className="relative z-50">
  <DialogBackdrop className="fixed inset-0 bg-black/40" />
  <div className="fixed inset-0 flex items-center justify-center p-4">
    <DialogPanel className="max-w-md rounded-xl bg-white p-5">
      <DialogTitle className="font-semibold">Edit profile</DialogTitle>
      {/* form fields */}
      <button onClick={() => setOpen(false)}>Cancel</button>
    </DialogPanel>
  </div>
</Dialog>

Dialog (Modal): daisyUI

import { useRef } from "react";

const ref = useRef<HTMLDialogElement>(null);

<button className="btn" onClick={() => ref.current?.showModal()}>Edit profile</button>
<dialog ref={ref} className="modal">
  <div className="modal-box">
    <h3 className="text-lg font-bold">Edit profile</h3>
    {/* form fields */}
    <div className="modal-action">
      <form method="dialog"><button className="btn">Cancel</button></form>
    </div>
  </div>
  <form method="dialog" className="modal-backdrop"><button>close</button></form>
</dialog>

Dialog (Modal): Flowbite React

import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from "flowbite-react";
import { useState } from "react";

const [open, setOpen] = useState(false);

<Button onClick={() => setOpen(true)}>Edit profile</Button>
<Modal show={open} onClose={() => setOpen(false)} size="md">
  <ModalHeader>Edit profile</ModalHeader>
  <ModalBody>{/* form fields */}</ModalBody>
  <ModalFooter>
    <Button color="alternative" onClick={() => setOpen(false)}>Cancel</Button>
    <Button onClick={() => setOpen(false)}>Save</Button>
  </ModalFooter>
</Modal>

Dialog (Modal): MUI

import Button from "@mui/material/Button";
import Dialog from "@mui/material/Dialog";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogActions from "@mui/material/DialogActions";
import { useState } from "react";

const [open, setOpen] = useState(false);

<Button variant="contained" onClick={() => setOpen(true)}>Edit profile</Button>
<Dialog open={open} onClose={() => setOpen(false)}>
  <DialogTitle>Edit profile</DialogTitle>
  <DialogContent>{/* form fields */}</DialogContent>
  <DialogActions>
    <Button onClick={() => setOpen(false)}>Cancel</Button>
    <Button variant="contained" onClick={() => setOpen(false)}>Save</Button>
  </DialogActions>
</Dialog>

Dropdown-Menü

Menüs brauchen Pfeiltasten-Navigation, Type-ahead und korrekte Rollen. Radix, Headless UI, shadcn/ui und MUI erledigen das; die <details>-Variante von daisyUI öffnet und schließt sich ohne JavaScript, bietet aber keine Pfeiltasten-Navigation.

Dropdown-Menü: shadcn/ui

import {
  DropdownMenu, DropdownMenuContent, DropdownMenuItem,
  DropdownMenuSeparator, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

<DropdownMenu>
  <DropdownMenuTrigger asChild><Button variant="outline">Options</Button></DropdownMenuTrigger>
  <DropdownMenuContent align="start">
    <DropdownMenuItem onSelect={rename}>Rename</DropdownMenuItem>
    <DropdownMenuItem onSelect={duplicate}>Duplicate</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem variant="destructive">Delete</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Dropdown-Menü: Radix Primitives

import { DropdownMenu } from "radix-ui";

<DropdownMenu.Root>
  <DropdownMenu.Trigger>Options</DropdownMenu.Trigger>
  <DropdownMenu.Portal>
    <DropdownMenu.Content sideOffset={6} className="rounded-lg bg-white p-1 shadow-lg">
      <DropdownMenu.Item onSelect={rename} className="data-[highlighted]:bg-black/5">Rename</DropdownMenu.Item>
      <DropdownMenu.Item onSelect={duplicate}>Duplicate</DropdownMenu.Item>
      <DropdownMenu.Separator className="my-1 h-px bg-black/10" />
      <DropdownMenu.Item disabled>Move</DropdownMenu.Item>
    </DropdownMenu.Content>
  </DropdownMenu.Portal>
</DropdownMenu.Root>

Dropdown-Menü: Headless UI

import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";

<Menu>
  <MenuButton>Options</MenuButton>
  <MenuItems anchor="bottom start" className="rounded-lg bg-white p-1 shadow-lg">
    <MenuItem>
      <button onClick={rename} className="block w-full data-focus:bg-black/5">Rename</button>
    </MenuItem>
    <MenuItem>
      <button onClick={duplicate} className="block w-full data-focus:bg-black/5">Duplicate</button>
    </MenuItem>
  </MenuItems>
</Menu>

Dropdown-Menü: daisyUI

<details className="dropdown">
  <summary className="btn">Options</summary>
  <ul className="menu dropdown-content z-1 w-52 rounded-box bg-base-100 p-2 shadow-sm">
    <li><button onClick={rename}>Rename</button></li>
    <li><button onClick={duplicate}>Duplicate</button></li>
  </ul>
</details>

Dropdown-Menü: Flowbite React

import { Dropdown, DropdownDivider, DropdownItem } from "flowbite-react";

<Dropdown label="Options" dismissOnClick>
  <DropdownItem onClick={rename}>Rename</DropdownItem>
  <DropdownItem onClick={duplicate}>Duplicate</DropdownItem>
  <DropdownDivider />
  <DropdownItem>Delete</DropdownItem>
</Dropdown>

Dropdown-Menü: MUI

import Button from "@mui/material/Button";
import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
import { useState } from "react";

const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
const close = () => setAnchorEl(null);

<Button onClick={(e) => setAnchorEl(e.currentTarget)}>Options</Button>
<Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={close}>
  <MenuItem onClick={() => { rename(); close(); }}>Rename</MenuItem>
  <MenuItem onClick={() => { duplicate(); close(); }}>Duplicate</MenuItem>
</Menu>

Tabs

Korrekte Tabs brauchen role="tablist", role="tab", aria-selected und Wechsel zwischen Tabs per Pfeiltasten. In daisyUI und MUI verknüpfst du Panels und IDs selbst; die anderen verbinden sie für dich.

Tabs: shadcn/ui

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

<Tabs defaultValue="account">
  <TabsList>
    <TabsTrigger value="account">Account</TabsTrigger>
    <TabsTrigger value="billing">Billing</TabsTrigger>
  </TabsList>
  <TabsContent value="account">Account settings</TabsContent>
  <TabsContent value="billing">Billing settings</TabsContent>
</Tabs>

Tabs: Radix Primitives

import { Tabs } from "radix-ui";

<Tabs.Root defaultValue="account">
  <Tabs.List aria-label="Settings">
    <Tabs.Trigger value="account" className="data-[state=active]:font-semibold">Account</Tabs.Trigger>
    <Tabs.Trigger value="billing" className="data-[state=active]:font-semibold">Billing</Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="account">Account settings</Tabs.Content>
  <Tabs.Content value="billing">Billing settings</Tabs.Content>
</Tabs.Root>

Tabs: Headless UI

import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@headlessui/react";

<TabGroup>
  <TabList>
    <Tab className="data-selected:font-semibold">Account</Tab>
    <Tab className="data-selected:font-semibold">Billing</Tab>
  </TabList>
  <TabPanels>
    <TabPanel>Account settings</TabPanel>
    <TabPanel>Billing settings</TabPanel>
  </TabPanels>
</TabGroup>

Tabs: daisyUI

const [tab, setTab] = useState("account");

<div role="tablist" className="tabs tabs-box">
  <button role="tab" aria-selected={tab === "account"}
    className={"tab " + (tab === "account" ? "tab-active" : "")}
    onClick={() => setTab("account")}>Account</button>
  <button role="tab" aria-selected={tab === "billing"}
    className={"tab " + (tab === "billing" ? "tab-active" : "")}
    onClick={() => setTab("billing")}>Billing</button>
</div>
<div role="tabpanel">{tab === "account" ? "Account settings" : "Billing settings"}</div>

Tabs: Flowbite React

import { TabItem, Tabs } from "flowbite-react";

<Tabs aria-label="Settings" variant="underline" onActiveTabChange={(i) => console.log(i)}>
  <TabItem active title="Account">Account settings</TabItem>
  <TabItem title="Billing">Billing settings</TabItem>
</Tabs>

Tabs: MUI

import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab";
import { useState } from "react";

const [tab, setTab] = useState(0);

<Tabs value={tab} onChange={(_, next) => setTab(next)} aria-label="Settings">
  <Tab label="Account" id="tab-0" aria-controls="panel-0" />
  <Tab label="Billing" id="tab-1" aria-controls="panel-1" />
</Tabs>
<div role="tabpanel" id={`panel-${tab}`} aria-labelledby={`tab-${tab}`}>
  {tab === 0 ? "Account settings" : "Billing settings"}
</div>

Switch (Toggle)

Ein Switch ist ein Ein/Aus-Steuerelement, das als role="switch" angesagt wird. daisyUI stylt eine echte Checkbox, wodurch das native Formularverhalten erhalten bleibt; die anderen rendern einen Button mit der Rolle switch.

Switch (Toggle): shadcn/ui

import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";

<div className="flex items-center gap-2">
  <Switch id="email-alerts" checked={on} onCheckedChange={setOn} />
  <Label htmlFor="email-alerts">Email notifications</Label>
</div>

Switch (Toggle): Radix Primitives

import { Switch } from "radix-ui";

<Switch.Root id="email-alerts" checked={on} onCheckedChange={setOn}
  className="h-6 w-11 rounded-full bg-black/20 data-[state=checked]:bg-blue-500">
  <Switch.Thumb className="block h-5 w-5 rounded-full bg-white transition-transform data-[state=checked]:translate-x-5" />
</Switch.Root>
<label htmlFor="email-alerts">Email notifications</label>

Switch (Toggle): Headless UI

import { Field, Label, Switch } from "@headlessui/react";

<Field className="flex items-center gap-2">
  <Switch checked={on} onChange={setOn}
    className="group h-6 w-11 rounded-full bg-black/20 data-checked:bg-blue-500">
    <span className="block h-5 w-5 rounded-full bg-white transition group-data-checked:translate-x-5" />
  </Switch>
  <Label>Email notifications</Label>
</Field>

Switch (Toggle): daisyUI

<label className="flex items-center gap-2">
  <input type="checkbox" className="toggle toggle-primary"
    checked={on} onChange={(e) => setOn(e.target.checked)} />
  Email notifications
</label>

Switch (Toggle): Flowbite React

import { ToggleSwitch } from "flowbite-react";

<ToggleSwitch checked={on} onChange={setOn} label="Email notifications" />

Switch (Toggle): MUI

import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch";

<FormControlLabel
  control={<Switch checked={on} onChange={(e) => setOn(e.target.checked)} />}
  label="Email notifications"
/>

Toast (Benachrichtigung)

Bei Toasts unterscheiden sich die Bibliotheken am stärksten. Manche geben dir eine Komponente, die du über State steuerst, manche eine Funktion, die du von überall aufrufst, und Headless UI lässt ihn ganz weg.

Toast (Benachrichtigung): shadcn/ui

// after: npx shadcn add sonner
import { Toaster } from "@/components/ui/sonner";
import { toast } from "sonner";

// once, near the root of your app
<Toaster />

// anywhere
<Button onClick={() => toast("Changes saved", {
  description: "Your profile is up to date.",
  action: { label: "Undo", onClick: undo },
})}>
  Save
</Button>

Toast (Benachrichtigung): Radix Primitives

import { Toast } from "radix-ui";

<Toast.Provider duration={4000}>
  <button onClick={() => setOpen(true)}>Save</button>
  <Toast.Root open={open} onOpenChange={setOpen} className="rounded-lg bg-white p-3 shadow-lg">
    <Toast.Title>Changes saved</Toast.Title>
    <Toast.Description>Your profile is up to date.</Toast.Description>
    <Toast.Action altText="Undo the save" onClick={undo}>Undo</Toast.Action>
  </Toast.Root>
  <Toast.Viewport className="fixed bottom-4 right-4 w-80" />
</Toast.Provider>

Toast (Benachrichtigung): Headless UI

// Headless UI has no toast component. Common choices:
// pair it with a small toast package, or build one from
// Transition plus an aria-live region:
import { Transition } from "@headlessui/react";

<div aria-live="polite" className="fixed bottom-4 right-4">
  <Transition show={open}>
    <div className="rounded-lg bg-white p-3 shadow-lg transition data-closed:opacity-0">
      Changes saved
    </div>
  </Transition>
</div>

Toast (Benachrichtigung): daisyUI

{/* daisyUI positions and stacks; showing and hiding is your state */}
{open && (
  <div className="toast toast-end toast-bottom" role="status">
    <div className="alert alert-success">
      <span>Changes saved</span>
    </div>
  </div>
)}

Toast (Benachrichtigung): Flowbite React

import { Toast, ToastToggle } from "flowbite-react";

{open && (
  <Toast className="fixed bottom-4 right-4">
    <div className="text-sm font-normal">Changes saved</div>
    <ToastToggle onDismiss={() => setOpen(false)} />
  </Toast>
)}

Toast (Benachrichtigung): MUI

import Snackbar from "@mui/material/Snackbar";
import Button from "@mui/material/Button";

<Snackbar
  open={open}
  autoHideDuration={4000}
  onClose={() => setOpen(false)}
  message="Changes saved"
  action={<Button size="small" onClick={undo}>Undo</Button>}
/>

Welche Bibliothek für welchen Projekttyp

ProjektPasst gutWarum
Marketing-Website oder Landingpage in TailwinddaisyUI oder reines TailwindÜberwiegend statische Seiten brauchen Buttons, Karten und ein Menü, keine JavaScript-Komponentenschicht. Die Klassen von daisyUI funktionieren auch auf Seiten ohne React.
SaaS-Produkt mit eigener Markeshadcn/ui oder Radix / Headless UI, selbst gestyltDu bekommst barrierefreies Verhalten, ohne den Look eines anderen Produkts zu übernehmen, und kannst dein Designsystem exakt treffen.
Eigenes Designsystem oder eigene KomponentenbibliothekRadix Primitives (oder Base UI), Headless UIUngestylte Primitives sind die Schicht, über der du die Styles selbst besitzen willst. shadcn/ui ist selbst ein Beispiel für diesen Ansatz.
Internes Tool, Admin-Panel, DashboardMUI oder shadcn/uiDie Breite von MUI (Tabellen, Datumsauswahl über MUI X, Formulare) spart die meiste Zeit, wenn Ausliefern wichtiger ist als der Look. shadcn/ui, wenn du schon mit Tailwind arbeitest.
Prototyp oder Hackathon mit TailwindFlowbite React oder daisyUIFertig aussehende Komponenten mit sehr wenig Styling-Aufwand. Plane eine Überarbeitung ein, falls aus dem Prototyp ein Produkt wird.
Team, das bereits Material Design nutzt (oder eine Oberfläche im Android-Stil)MUIEs setzt Material Design direkt um, sodass Designer und Entwickler dasselbe Vokabular teilen.
Strenge Anforderungen an Barrierefreiheit (öffentlicher Sektor, Großunternehmen)Radix Primitives, Headless UI, MUI oder shadcn/ui daraufTastatur- und Fokusverhalten sind eingebaut und dokumentiert. Egal, was du wählst, teste trotzdem mit Tastatur und Screenreader; keine Bibliothek macht eine Seite von allein barrierefrei.

Fragen, die du vor der Wahl klären solltest

Zu den Hooks, auf denen diese Komponenten aufbauen, siehe den React-Hooks-Spickzettel. Zu den Utility-Klassen in den Snippets siehe den Tailwind-Spickzettel, und zu den Zuständen hover, focus und disabled, die jeder Button braucht, CSS-Button-Zustände. Außerdem findest du fertige React- und Tailwind-Bausteine für Modals, Buttons und Navigation in unserer Komponenten-Galerie.

Quellen

Geprüft im Oktober 2026: die Dokumentation und der Changelog von shadcn/ui (ui.shadcn.com), das GitHub-Repository shadcn-ui/ui; die Dokumentation von Radix Primitives einschließlich der Übersicht zur Barrierefreiheit (radix-ui.com/primitives); Headless UI (headlessui.com); die Seiten zu Installation, Upgrade und Komponenten von daisyUI (daisyui.com); die Dokumentation von MUI Material UI (mui.com); sowie die Einträge in der npm-Registry für shadcn, radix-ui, @headlessui/react, daisyui, flowbite-react und @mui/material zu Versionen, Lizenzen und Peer-Dependencies.

Häufige Fragen

Ist shadcn/ui eine Komponentenbibliothek?

Nicht im üblichen Sinn. Laut eigener Dokumentation ist es keine Komponentenbibliothek, sondern ein Weg, deine eigene zu bauen: Eine CLI kopiert den Komponenten-Quellcode in dein Projekt, und du bearbeitest und pflegst diesen Code. Die interaktiven Teile basieren auf einer Headless-Bibliothek, bei neuen Projekten seit Juli 2026 standardmäßig Base UI, wobei Radix weiterhin unterstützt wird.

Was ist der Unterschied zwischen Radix und Headless UI?

Beide sind ungestylte, barrierefreie React-Komponenten. Radix Primitives hat eine größere Sammlung, unter anderem mit Toast, Tooltip, Slider und Toolbar, und unterstützt React 16.8 bis 19. Headless UI stammt vom Tailwind-CSS-Team, hat eine kleinere Sammlung ohne Toast und Tooltip und erfordert React 18 oder 19.

Funktioniert daisyUI mit React?

Ja. daisyUI ist ein Tailwind-CSS-Plugin, das Klassennamen wie btn, modal und tabs hinzufügt, die du in JSX wie jede andere Tailwind-Klasse verwendest. Es liefert keine React-Komponenten, daher wird Zustand wie das Öffnen eines Modals oder der Wechsel von Tabs in deinem eigenen React-Code verwaltet.

Sind diese Bibliotheken für kommerzielle Nutzung kostenlos?

Ja. shadcn/ui, Radix Primitives, Headless UI, daisyUI, flowbite-react und das Kernpaket Material UI von MUI stehen zum Zeitpunkt des Schreibens (Oktober 2026) alle unter MIT-Lizenz. Die Komponenten von MUI X Pro und Premium sowie die Pro-Blöcke von Flowbite sind separate kommerzielle Produkte.

Welche React UI-Bibliothek ist am besten für Barrierefreiheit?

Radix Primitives, Headless UI und MUI bauen Tastaturnavigation und Fokusverwaltung in ihre Komponenten ein, und shadcn/ui übernimmt das von seiner Primitive-Schicht. daisyUI setzt auf native HTML-Elemente, ARIA und Tastaturverhalten ergänzt du also selbst. Egal, welche du nutzt, teste mit Tastatur und Screenreader.

Kann ich MUI mit Tailwind CSS verwenden?

Ja, aber sie stylen unterschiedlich: MUI nutzt Emotion und ein JavaScript-Theme, Tailwind nutzt Utility-Klassen. Sie funktionieren nebeneinander, allerdings musst du Farben und Abstände zwischen den beiden Themes selbst synchron halten. Teams, die alles in Tailwind wollen, wählen stattdessen meist shadcn/ui oder eine Headless-Bibliothek.

Live: Radix Primitives {title} (ungestylte Bibliothek, unsere Tailwind-Klassen)

Profil bearbeiten

Drück Tab: Der Fokus bleibt im Dialog. Drück Escape oder klick daneben, um ihn zu schließen.

Anzeigename

Abbrechen

Speichern

Schließen

noch nichts

Optionen

Umbenennen

Duplizieren

Verschieben (deaktiviert)

Versteckte Dateien anzeigen

Probier die Pfeiltasten und Type-ahead aus. Zuletzt gewählt: {last}

Einstellungen

Konto

Abrechnung

Team

Panel mit Kontoeinstellungen. Nutze auf den Tabs die Pfeiltasten Links und Rechts.

Panel Abrechnung.

Panel Team.

E-Mail-Benachrichtigungen: an

E-Mail-Benachrichtigungen: aus

Änderungen speichern

Änderungen gespeichert

In dieser Demo {n} Mal gespeichert.

In dieser Demo {n} Mal gespeichert.

Speichern rückgängig machen

Rückgängig

Kostenlos starten · Keine Kreditkarte nötig

Verwandt: Ratgeber

Produkt

Für wen

Funktionen

Ressourcen

Unternehmen

Sitemap