shadcn/ui, Radix, Headless UI, daisyUI, Flowbite en MUI verschillen vooral in styling: Radix en Headless UI zijn ongestyled, daisyUI en Flowbite zijn vooraf gestyled met Tailwind, MUI is Material Design, en shadcn/ui kopieert gestylede code naar uw project. Hier staan dezelfde zes componenten in elke bibliotheek, plus welke u kiest.
Deze zes bibliotheken lossen verschillende problemen op, en daarom heeft de vraag "welke is de beste" geen eenduidig antwoord. Twee ervan (Radix Primitives en Headless UI) geven u gedrag en toegankelijkheid zonder styling. Twee (daisyUI en Flowbite) geven u een kant-en-klare Tailwind-look. MUI geeft u een compleet designsysteem met een eigen styling-engine. shadcn/ui is helemaal geen package: het kopieert gestylede componentcode naar uw project, gebouwd op een headless laag eronder.
Alle feiten hieronder (versies, licenties, vereisten) zijn in oktober 2026 gecontroleerd aan de hand van de officiële documentatie, de GitHub-repository en de npm-vermelding van elk project. Versies veranderen snel, dus beschouw de getallen als "op het moment van schrijven".
| shadcn/ui | Radix Primitives | Headless UI | daisyUI | Flowbite React | MUI (Material UI) | |
|---|---|---|---|---|---|---|
| Wat u installeert | een CLI die componentcode naar uw repo kopieert | npm-packages (radix-ui of één per component) | @headlessui/react | daisyui Tailwind-plugin | flowbite-react | @mui/material plus Emotion |
| Stylingmodel | Tailwind-classes in code die van u is; thema via CSS-variabelen | ongestyled; u voegt classes toe, status via data-state-attributen | ongestyled; status via data-*-attributen, ontworpen voor Tailwind | CSS-componentclasses (btn, modal) en thema's | vooraf gestylede Tailwind-componenten, aan te passen via thema's | Material Design, CSS-in-JS (sx-prop, thema-object) |
| Versie (okt 2026) | CLI shadcn 4.x (geen runtime-package) | radix-ui 1.8; losse packages 1.x en 2.x | 2.2 | 5.x | 0.12 (vóór 1.0) | 9.x |
| Licentie | MIT | MIT | MIT | MIT | MIT | MIT (betaalde MUI X Pro/Premium staan los) |
| React nodig | ja | 16.8 tot 19 | 18 of 19 | nee (gewone HTML en CSS) | 18 of 19 | 17, 18 of 19 |
| Tailwind nodig | ja (v4 in de huidige documentatie) | nee | nee, maar wel bedoeld ervoor | ja, Tailwind 4 voor daisyUI 5 | ja, Tailwind 3 of 4 | nee |
| Aanpak van toegankelijkheid | neemt die over van de onderliggende primitive-laag (Base UI of Radix) | volgt de WAI-ARIA Authoring Practices; toetsenbord en focus ingebouwd | omschreven als "volledig toegankelijk"; toetsenbord en focus ingebouwd | leunt op native elementen (<dialog>, <details>); ARIA en gedrag voegt u zelf toe | React-componenten met positionering via Floating UI; test het toetsenbordgebruik zelf | ARIA en toetsenbordafhandeling per component, per component gedocumenteerd |
| Heeft een toast | ja, via Sonner | ja (Toast) | nee | ja (alleen een layout-class) | ja (Toast) | ja (Snackbar) |
De bundlegrootte hebben we bewust uit de tabel gelaten. De getallen hangen sterk af van welke componenten u importeert, of uw bundler ze tree-shaket en (bij daisyUI) hoeveel CSS Tailwind genereert voor de classes die u gebruikt. Eén "kB"-getal per bibliotheek zou meer misleiden dan helpen. Meet uw eigen build: draai de analyzer van uw bundler vóór en na het toevoegen van de componenten die u echt nodig hebt.
Wat het is. shadcn/ui omschrijft zichzelf als "geen componentbibliotheek" maar als "de manier waarop u uw componentbibliotheek bouwt". U draait de CLI (npx shadcn init, daarna npx shadcn add button) en die schrijft de componentcode in uw project. Vanaf dat moment is de code van u om te bewerken; er is geen shadcn-runtimepackage om te upgraden.
Styling. Tailwind CSS-classes in de gekopieerde bestanden, met kleuren en radii als CSS-variabelen, zodat u op één plek een ander thema kunt instellen. Varianten worden meestal gedefinieerd met class-variance-authority.
Onder de motorkap. De interactieve onderdelen draaien op een headless bibliotheek. Volgens de changelog van shadcn/ui gebruiken nieuwe projecten sinds juli 2026 standaard Base UI, en wordt Radix "niet uitgefaseerd": beide worden ondersteund. De toast is gebouwd op Sonner, een apart opensource-toastpackage.
Licentie en versie. MIT (GitHub-repository shadcn-ui/ui). Het CLI-package shadcn stond op het moment van schrijven op 4.x op npm.
Let op. Omdat de code van u is, is het onderhoud dat ook. Fixes upstream komen niet automatisch in uw kopieën terecht, en verschillende projecten groeien na verloop van tijd uit elkaar.
Wat het is. Een set ongestylede, toegankelijke React-componenten (dialog, dropdownmenu, tabs, switch, toast, tooltip, popover en meer). U kunt alles installeren via het ene package radix-ui (1.8 op het moment van schrijven) of één package per component, zoals @radix-ui/react-dialog.
Styling. Standaard geen. Elk onderdeel rendert een gewoon element dat u met elke methode kunt stylen. De status wordt beschikbaar gemaakt als data-attributen, bijvoorbeeld data-state="open" of data-highlighted, die goed samengaan met de data-[state=open]:-varianten van Tailwind.
Toegankelijkheid. Volgens de documentatie van Radix volgen de primitives de WAI-ARIA Authoring Practices, bieden ze toetsenbordondersteuning en beheren ze de focus (bijvoorbeeld door de focus binnen een open dialoog vast te houden en die bij het sluiten terug te geven).
Licentie en vereisten. MIT. Het bereik van de npm-peer-dependency dekt React 16.8 tot en met 19.
Let op. Elke stijl schrijft u zelf. Radix levert geen Button-primitive: gebruik een native <button>, of de utility Slot om props samen te voegen in uw eigen element.
Wat het is. Ongestylede componenten van het Tailwind CSS-team. Het React-package, @headlessui/react (2.2 op het moment van schrijven), bevat Button, Checkbox, Combobox, Dialog, Disclosure, Fieldset, Input, Listbox, Menu (dropdown), Popover, Radio Group, Select, Switch, Tabs, Textarea en Transition.
Styling. Ongestyled. Componenten maken hun status beschikbaar via data-attributen (data-open, data-checked, data-selected, data-focus), dus u stylet ze met Tailwind-varianten zoals data-checked:bg-blue-600 (syntaxis van Tailwind 4) of data-[checked]:bg-blue-600 (Tailwind 3).
Toegankelijkheid. De site omschrijft de componenten als "volledig ongestyled, volledig toegankelijk". Toetsenbordnavigatie, het vasthouden van de focus in dialogen en de ARIA-koppelingen zijn ingebouwd.
Licentie en vereisten. MIT. React 18 of 19 (npm-peer-dependency).
Let op. De set is kleiner dan die van Radix: er is geen toast, tooltip of slider, dus daarvoor hebt u een ander package nodig.
Wat het is. Een Tailwind CSS-plugin die componentclassnamen toevoegt zoals btn, modal, dropdown, tabs, toggle en toast, plus een set kleurthema's. Het levert CSS, geen React-componenten, dus het werkt met elk framework of zonder framework.
Styling. Semantische classes met modifiers (btn btn-primary btn-sm) die u nog steeds kunt combineren met gewone Tailwind-utilities. Thema's wisselen via CSS-variabelen.
Vereisten. daisyUI 5 (voor het eerst uitgebracht in februari 2025, 5.x op het moment van schrijven) is gericht op Tailwind CSS 4; de upgradegids laat u eerst Tailwind bijwerken. U installeert het met één regel @plugin "daisyui"; in uw CSS.
Toegankelijkheid. Omdat het alleen CSS is, komt het gedrag uit native HTML: de modal gebruikt het <dialog>-element (Escape sluit hem en de browser regelt de focus), dropdowns gebruiken <details> of de popover-API. Alles daarbuiten (ARIA voor tabs, toasts aankondigen) is uw taak.
Licentie. MIT.
Let op. In React koppelt u de status zelf (bijvoorbeeld door showModal() via een ref aan te roepen). Er is geen afhandeling van pijltjestoetsen voor menu's of tabs, tenzij u die toevoegt.
Wat het is. React-componenten (flowbite-react) gestyled met Tailwind, van het Flowbite-project. Het bevat Button, Modal, Dropdown, Tabs, ToggleSwitch, Toast, Navbar, Sidebar, Datepicker en meer.
Styling. Vooraf gestyled met Tailwind-classes, aan te passen via een thema-object en een theme-prop op elke component.
Vereisten en versie. Versie 0.12 op het moment van schrijven: het heeft 1.0 nog niet bereikt, dus reken op breaking changes tussen minor-versies. De npm-peer-dependencies zijn React 18 of 19 en Tailwind CSS 3 of 4. Het gebruikt Floating UI voor de positionering van dropdowns en tooltips.
Toegankelijkheid. Componenten renderen de verwachte rollen voor gangbare patronen, maar we vonden geen gepubliceerde toegankelijkheidsverklaring die vergelijkbaar is met die van Radix. Test het gedrag met toetsenbord en schermlezer voor de componenten waarop u vertrouwt.
Licentie. MIT (de opensource-bibliotheek; Flowbite verkoopt daarnaast aparte Pro-blokken en ontwerpbestanden).
Wat het is. In eigen woorden "een opensource React-componentbibliotheek die Material Design van Google implementeert." Het is de grootste set in deze vergelijking, met componenten voor dataweergave, invoer, navigatie, layout en feedback.
Styling. CSS-in-JS. Standaard gebruikt het Emotion (@emotion/react en @emotion/styled zijn peer-dependencies van @mui/material 9). U stelt het thema in met createTheme en stylet losse gevallen met de sx-prop. Het kan naast Tailwind bestaan, maar de twee themasystemen delen geen tokens, tenzij u ze koppelt.
Versie en licentie. Versie 9 (9.0.0 verscheen in april 2026). De kernbibliotheek is MIT. Geavanceerde functies voor datagrids, datums en grafieken in MUI X Pro en Premium vallen onder commerciële licenties.
Toegankelijkheid. Componenten worden geleverd met ARIA-attributen en toetsenbordafhandeling, en de componentpagina's in de documentatie van MUI beschrijven het toegankelijkheidsgedrag per component.
Let op. Afstappen van de Material-look kost echt werk aan het thema, en CSS-in-JS vraagt extra configuratie met React Server Components.
Hieronder zijn dezelfde knop, dialoog, dropdownmenu, tabs, switch en toast zes keer geschreven, één keer in de gedocumenteerde API van elke bibliotheek. Elk fragment is originele code die voor deze pagina is geschreven (niet gekopieerd uit de documentatie van de bibliotheken), gebruikt de huidige hoofdversie van elke bibliotheek en is ingekort tot de delen die verschillen. Live, klikbare versies worden alleen voor Radix Primitives getoond, omdat Radix de bibliotheek is die op deze site is geïnstalleerd. Ze zijn gestyled met onze eigen Tailwind-classes, omdat Radix geen stijlen meelevert. Van de andere vijf bibliotheken tonen we geen live versies, zodat niets hier hun look nabootst.
De meeste bibliotheken leveren een knop met varianten. Merk op dat Radix en Headless UI de look aan u overlaten, terwijl daisyUI varianten als classes uitdrukt en de rest als props.
// 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>
// 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} />;
}
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 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>
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>
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>
In een dialoog zit het verborgen toegankelijkheidswerk: de focus vasthouden, sluiten met Escape, de focus teruggeven aan de trigger, labels. De headless bibliotheken en MUI doen dit in JavaScript; daisyUI leunt op het native <dialog>-element, dat Escape en focus in de browser afhandelt.
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>
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>
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>
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>
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>
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>
Menu's hebben navigatie met pijltjestoetsen, type-ahead en de juiste rollen nodig. Radix, Headless UI, shadcn/ui en MUI regelen dat; de <details>-versie van daisyUI opent en sluit zonder JavaScript, maar voegt geen navigatie met pijltjestoetsen toe.
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>
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>
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>
<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>
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>
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>
Correcte tabs hebben role="tablist", role="tab", aria-selected en verplaatsing met pijltjestoetsen tussen tabs nodig. In daisyUI en MUI koppelt u panelen en ID's zelf; de andere doen dat voor u.
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>
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>
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>
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>
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>
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>
Een switch is een aan/uit-bediening die wordt aangekondigd als role="switch". daisyUI stylet een echte checkbox, waardoor het native formuliergedrag behouden blijft; de andere renderen een knop met de switch-rol.
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>
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>
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>
<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>
import { ToggleSwitch } from "flowbite-react";
<ToggleSwitch checked={on} onChange={setOn} label="Email notifications" />
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"
/>
Bij toasts verschillen de bibliotheken het meest. Sommige geven u een component die u met state bestuurt, andere een functie die u overal kunt aanroepen, en Headless UI laat het helemaal weg.
// 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>
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>
// 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>
{/* 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>
)}
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>
)}
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>}
/>
| Project | Past goed | Waarom |
|---|---|---|
| Marketingsite of landingspagina in Tailwind | daisyUI, of gewoon Tailwind | Grotendeels statische pagina's hebben knoppen, kaarten en een menu nodig, geen JavaScript-componentlaag. De classes van daisyUI werken ook op pagina's zonder React. |
| SaaS-product met een eigen merk | shadcn/ui, of Radix / Headless UI door u gestyled | U krijgt toegankelijk gedrag zonder de look van een ander product over te nemen, en u kunt uw designsysteem precies volgen. |
| Uw eigen designsysteem of componentbibliotheek bouwen | Radix Primitives (of Base UI), Headless UI | Ongestylede primitives zijn precies de laag waarop u zelf de stijlen wilt bepalen. shadcn/ui is zelf een voorbeeld van deze aanpak. |
| Interne tool, adminpaneel, dashboard | MUI, of shadcn/ui | De breedte van MUI (tabellen, datumkiezers via MUI X, formulieren) bespaart de meeste tijd als de look minder belangrijk is dan opleveren. shadcn/ui als u al met Tailwind werkt. |
| Prototype of hackathon met Tailwind | Flowbite React of daisyUI | Afgewerkt ogende componenten met heel weinig stylingwerk. Plan een herziening als het prototype een product wordt. |
| Team dat al Material Design gebruikt (of een UI in Android-stijl) | MUI | Het implementeert Material Design direct, dus ontwerpers en ontwikkelaars delen één vocabulaire. |
| Strenge toegankelijkheidseisen (overheid, enterprise) | Radix Primitives, Headless UI, MUI, of shadcn/ui daarbovenop | Toetsenbord- en focusgedrag zijn ingebouwd en gedocumenteerd. Wat u ook kiest, test toch met een toetsenbord en een schermlezer; geen enkele bibliotheek maakt een pagina uit zichzelf toegankelijk. |
Voor de hooks waarop deze componenten zijn gebouwd, zie de React hooks cheat sheet. Voor de utility-classes die in de fragmenten worden gebruikt, zie de Tailwind cheat sheet, en voor de hover-, focus- en disabled-statussen die elke knop nodig heeft, CSS-knopstatussen. U kunt in onze componentengalerij ook kant-en-klare React- en Tailwind-modals, knoppen en navigatie bekijken.
Gecontroleerd in oktober 2026: de documentatie en changelog van shadcn/ui (ui.shadcn.com), de GitHub-repository shadcn-ui/ui; de documentatie van Radix Primitives, inclusief het toegankelijkheidsoverzicht (radix-ui.com/primitives); Headless UI (headlessui.com); de installatie-, upgrade- en componentpagina's van daisyUI (daisyui.com); de documentatie van MUI Material UI (mui.com); en de vermeldingen in het npm-register voor shadcn, radix-ui, @headlessui/react, daisyui, flowbite-react en @mui/material voor versies, licenties en peer-dependencies.
Niet in de gebruikelijke zin. Volgens de eigen documentatie is het geen componentbibliotheek maar een manier om uw eigen bibliotheek te bouwen: een CLI kopieert de componentcode naar uw project, en u bewerkt en onderhoudt die code. De interactieve onderdelen zijn gebouwd op een headless bibliotheek, sinds juli 2026 standaard Base UI voor nieuwe projecten, waarbij Radix nog steeds wordt ondersteund.
Beide zijn ongestylede, toegankelijke React-componenten. Radix Primitives heeft een grotere set, met onder meer toast, tooltip, slider en toolbar, en ondersteunt React 16.8 tot 19. Headless UI komt van het Tailwind CSS-team, heeft een kleinere set zonder toast of tooltip en vereist React 18 of 19.
Ja. daisyUI is een Tailwind CSS-plugin die classnamen toevoegt zoals btn, modal en tabs, dus u gebruikt die classes in JSX zoals elke andere Tailwind-class. Het levert geen React-componenten, dus state zoals het openen van een modal of het wisselen van tabs regelt u in uw eigen React-code.
Ja. shadcn/ui, Radix Primitives, Headless UI, daisyUI, flowbite-react en het kernpackage Material UI van MUI hebben op het moment van schrijven (oktober 2026) allemaal een MIT-licentie. De componenten van MUI X Pro en Premium en de Pro-blokken van Flowbite zijn aparte commerciële producten.
Radix Primitives, Headless UI en MUI bouwen toetsenbordnavigatie en focusbeheer in hun componenten in, en shadcn/ui neemt dat over van de onderliggende primitive-laag. daisyUI leunt op native HTML-elementen, dus ARIA en toetsenbordgedrag voegt u zelf toe. Wat u ook gebruikt, test met een toetsenbord en een schermlezer.
Dat kan, maar ze stylen op een andere manier: MUI gebruikt Emotion en een JavaScript-thema, Tailwind gebruikt utility-classes. Ze werken naast elkaar, maar u moet kleuren en spacing tussen de twee thema's zelf gelijk houden. Teams die alles in Tailwind willen, kiezen meestal shadcn/ui of een headless bibliotheek.
Live: Radix Primitives {title} (ongestylede bibliotheek, onze Tailwind-classes)
Profiel bewerken
Druk op Tab: de focus blijft binnen. Druk op Escape of klik erbuiten om te sluiten.
Weergavenaam
Annuleren
Opslaan
Sluiten
nog niets
Opties
Naam wijzigen
Dupliceren
Verplaatsen (uitgeschakeld)
Verborgen bestanden tonen
Probeer de pijltjestoetsen en type-ahead. Laatst gekozen: {last}
Instellingen
Account
Facturering
Team
Paneel met accountinstellingen. Gebruik de pijltjes Links en Rechts op de tabs.
Factureringspaneel.
Teampaneel.
E-mailmeldingen: aan
E-mailmeldingen: uit
Wijzigingen opslaan
Wijzigingen opgeslagen
{n} keer opgeslagen in deze demo.
{n} keer opgeslagen in deze demo.
Het opslaan ongedaan maken
Ongedaan maken
Gratis beginnen · Geen creditcard nodig