Bibliothèques de composants UI React comparées : shadcn/ui, Radix, Headless UI, daisyUI, Flowbite et MUI

shadcn/ui, Radix, Headless UI, daisyUI, Flowbite et MUI diffèrent surtout par le style : Radix et Headless UI sont sans style, daisyUI et Flowbite sont du Tailwind déjà stylé, MUI suit Material Design, et shadcn/ui copie du code stylé dans votre projet. Voici les mêmes six composants dans chacune, plus laquelle choisir.

En bref

Ces six bibliothèques résolvent des problèmes différents, c'est pourquoi la question « laquelle est la meilleure » n'a pas de réponse unique. Deux d'entre elles (Radix Primitives et Headless UI) fournissent le comportement et l'accessibilité sans aucun style. Deux autres (daisyUI et Flowbite) fournissent un rendu Tailwind déjà fini. MUI fournit un design system complet avec son propre moteur de styles. shadcn/ui n'est pas du tout un paquet : il copie le code source de composants stylés dans votre projet, construits sur une couche headless sous-jacente.

Tous les faits ci-dessous (versions, licences, prérequis) ont été vérifiés en octobre 2026 dans la documentation officielle, le dépôt GitHub et la fiche npm de chaque projet. Les versions évoluent vite, considérez donc les chiffres comme valables « au moment de la rédaction ».

Tableau comparatif

shadcn/uiRadix PrimitivesHeadless UIdaisyUIFlowbite ReactMUI (Material UI)
Ce que vous installezune CLI qui copie le code source des composants dans votre dépôtdes paquets npm (radix-ui ou un par composant)@headlessui/reactle plugin Tailwind daisyuiflowbite-react@mui/material plus Emotion
Modèle de styleclasses Tailwind dans du code qui vous appartient ; thème via des variables CSSsans style ; vous ajoutez les classes, l'état passe par des attributs data-statesans style ; l'état passe par des attributs data-*, conçu pour Tailwindclasses CSS de composants (btn, modal) et thèmescomposants Tailwind déjà stylés, personnalisables par thèmeMaterial Design, CSS-in-JS (prop sx, objet de thème)
Version (oct. 2026)CLI shadcn 4.x (aucun paquet d'exécution)radix-ui 1.8 ; paquets individuels en 1.x et 2.x2.25.x0.12 (avant la 1.0)9.x
LicenceMITMITMITMITMITMIT (les offres payantes MUI X Pro/Premium sont à part)
React requisoui16.8 à 1918 ou 19non (HTML et CSS simples)18 ou 1917, 18 ou 19
Tailwind requisoui (v4 dans la documentation actuelle)nonnon, mais pensé pour luioui, Tailwind 4 pour daisyUI 5oui, Tailwind 3 ou 4non
Approche de l'accessibilitéhéritée de sa couche de primitives (Base UI ou Radix)suit les WAI-ARIA Authoring Practices ; clavier et focus intégrésprésenté comme « entièrement accessible » ; clavier et focus intégréss'appuie sur les éléments natifs (<dialog>, <details>) ; vous ajoutez ARIA et le comportementcomposants React avec positionnement Floating UI ; testez vous-même l'usage au claviergestion ARIA et clavier par composant, documentée composant par composant
Propose un toastoui, via Sonneroui (Toast)nonoui (classe de mise en page seulement)oui (Toast)oui (Snackbar)

Nous avons volontairement laissé le poids du bundle hors du tableau. Les chiffres dépendent fortement des composants que vous importez, du tree-shaking effectué par votre bundler et (pour daisyUI) de la quantité de CSS que Tailwind génère pour les classes utilisées. Un chiffre unique en « kB » par bibliothèque induirait plus en erreur qu'il n'aiderait. Mesurez votre propre build : lancez l'analyseur de votre bundler avant et après l'ajout des composants dont vous avez réellement besoin.

Chaque bibliothèque en détail

shadcn/ui

Ce que c'est. shadcn/ui se décrit comme « pas une bibliothèque de composants » mais « la façon de construire votre bibliothèque de composants ». Vous lancez sa CLI (npx shadcn init, puis npx shadcn add button) et elle écrit le code source du composant dans votre projet. À partir de là, le code vous appartient et vous le modifiez librement ; il n'y a aucun paquet shadcn d'exécution à mettre à jour.

Style. Des classes Tailwind CSS dans les fichiers copiés, avec les couleurs et les arrondis en variables CSS pour changer de thème à un seul endroit. Les variantes sont généralement définies avec class-variance-authority.

Sous le capot. Les parties interactives reposent sur une bibliothèque headless. D'après le changelog de shadcn/ui, les nouveaux projets utilisent Base UI par défaut depuis juillet 2026, et Radix « n'est pas abandonné » : les deux sont pris en charge. Son toast est construit sur Sonner, un paquet de toasts open source distinct.

Licence et version. MIT (dépôt GitHub shadcn-ui/ui). Le paquet CLI shadcn était en 4.x sur npm au moment de la rédaction.

Points de vigilance. Comme le code vous appartient, sa maintenance aussi. Les correctifs en amont n'atteignent pas automatiquement vos copies, et les projets finissent par diverger avec le temps.

Radix Primitives

Ce que c'est. Un ensemble de composants React accessibles et sans style (dialog, menu déroulant, onglets, switch, toast, tooltip, popover et plus). Vous pouvez tout installer depuis le paquet unique radix-ui (1.8 au moment de la rédaction) ou un paquet par composant, comme @radix-ui/react-dialog.

Style. Aucun par défaut. Chaque partie produit un élément simple que vous pouvez styler avec n'importe quelle méthode. L'état est exposé par des attributs data, par exemple data-state="open" ou data-highlighted, qui se combinent bien avec les variantes data-[state=open]: de Tailwind.

Accessibilité. La documentation de Radix indique que les primitives suivent les WAI-ARIA Authoring Practices, prennent en charge le clavier et gèrent le focus (par exemple en le piégeant dans un dialogue ouvert et en le restituant à la fermeture).

Licence et prérequis. MIT. La plage de peer dependencies npm couvre React 16.8 à 19.

Points de vigilance. Vous écrivez vous-même tous les styles. Radix ne fournit pas de primitive Button : utilisez un <button> natif, ou l'utilitaire Slot pour fusionner les props dans votre propre élément.

Headless UI

Ce que c'est. Des composants sans style créés par l'équipe de Tailwind CSS. Le paquet React, @headlessui/react (2.2 au moment de la rédaction), comprend Button, Checkbox, Combobox, Dialog, Disclosure, Fieldset, Input, Listbox, Menu (menu déroulant), Popover, Radio Group, Select, Switch, Tabs, Textarea et Transition.

Style. Aucun. Les composants exposent leur état via des attributs data (data-open, data-checked, data-selected, data-focus), que vous stylez avec des variantes Tailwind comme data-checked:bg-blue-600 (syntaxe Tailwind 4) ou data-[checked]:bg-blue-600 (Tailwind 3).

Accessibilité. Son site décrit les composants comme « totalement sans style, entièrement accessibles ». La navigation au clavier, le piégeage du focus dans les dialogues et le câblage ARIA sont intégrés.

Licence et prérequis. MIT. React 18 ou 19 (peer dependency npm).

Points de vigilance. L'ensemble est plus restreint que Radix : il n'y a ni toast, ni tooltip, ni slider, il vous faudra donc un autre paquet pour ceux-là.

daisyUI

Ce que c'est. Un plugin Tailwind CSS qui ajoute des noms de classes de composants comme btn, modal, dropdown, tabs, toggle et toast, ainsi qu'un ensemble de thèmes de couleurs. Il fournit du CSS, pas des composants React, et fonctionne donc avec n'importe quel framework, ou sans.

Style. Des classes sémantiques avec modificateurs (btn btn-primary btn-sm) que vous pouvez toujours combiner avec les utilitaires Tailwind habituels. Les thèmes changent via des variables CSS.

Prérequis. daisyUI 5 (sorti pour la première fois en février 2025, en 5.x au moment de la rédaction) cible Tailwind CSS 4 ; son guide de mise à niveau vous fait d'abord mettre à jour Tailwind. Vous l'installez avec une seule ligne @plugin "daisyui"; dans votre CSS.

Accessibilité. Comme il ne s'agit que de CSS, le comportement vient du HTML natif : la modale utilise l'élément <dialog> (Escape la ferme et le navigateur gère le focus), les menus déroulants utilisent <details> ou l'API popover. Tout le reste (ARIA pour les onglets, annonce des toasts) est à votre charge.

Licence. MIT.

Points de vigilance. En React, vous câblez l'état vous-même (par exemple en appelant showModal() via une ref). Il n'y a aucune gestion des flèches du clavier pour les menus ou les onglets, sauf si vous l'ajoutez.

Flowbite React

Ce que c'est. Des composants React (flowbite-react) stylés avec Tailwind, issus du projet Flowbite. Il comprend Button, Modal, Dropdown, Tabs, ToggleSwitch, Toast, Navbar, Sidebar, Datepicker et plus.

Style. Déjà stylés avec des classes Tailwind, personnalisables via un objet de thème et une prop theme sur chaque composant.

Prérequis et version. Version 0.12 au moment de la rédaction : elle n'a pas atteint la 1.0, attendez-vous donc à des changements cassants entre versions mineures. Les peer dependencies npm sont React 18 ou 19 et Tailwind CSS 3 ou 4. Elle utilise Floating UI pour positionner menus déroulants et tooltips.

Accessibilité. Les composants produisent les rôles attendus pour les modèles courants, mais nous n'avons pas trouvé de déclaration d'accessibilité publiée comparable à celle de Radix. Testez le comportement au clavier et au lecteur d'écran des composants sur lesquels vous comptez.

Licence. MIT (la bibliothèque open source ; Flowbite vend aussi séparément des blocs Pro et des fichiers de design).

MUI (Material UI)

Ce que c'est. Selon ses propres termes, « une bibliothèque de composants React open source qui implémente le Material Design de Google ». C'est l'ensemble le plus vaste de ce comparatif, avec des composants d'affichage de données, de saisie, de navigation, de mise en page et de retour utilisateur.

Style. CSS-in-JS. Par défaut, il utilise Emotion (@emotion/react et @emotion/styled sont des peer dependencies de @mui/material 9). Vous le personnalisez avec createTheme et stylez les cas ponctuels avec la prop sx. Il peut cohabiter avec Tailwind, mais les deux systèmes de thème ne partagent pas de tokens tant que vous ne les reliez pas.

Version et licence. Version 9 (la 9.0.0 a été publiée en avril 2026). La bibliothèque de base est sous MIT. Les fonctions avancées de grille de données, de dates et de graphiques de MUI X Pro et Premium relèvent de licences commerciales.

Accessibilité. Les composants sont livrés avec des attributs ARIA et une gestion du clavier, et les pages de composants de la documentation MUI décrivent le comportement d'accessibilité de chacun.

Points de vigilance. S'éloigner du style Material demande un vrai travail de thème, et le CSS-in-JS exige une configuration supplémentaire avec les React Server Components.

Les mêmes six composants dans chaque bibliothèque

Ci-dessous, le même bouton, dialogue, menu déroulant, onglets, interrupteur et toast sont écrits six fois, une fois avec l'API documentée de chaque bibliothèque. Chaque extrait est du code original écrit pour cette page (et non copié de la documentation des bibliothèques), utilise la version majeure actuelle de chaque bibliothèque et se limite aux parties qui diffèrent. Des versions interactives et cliquables sont affichées pour Radix Primitives uniquement, car Radix est la bibliothèque installée sur ce site. Elles sont stylées avec nos propres classes Tailwind, puisque Radix ne fournit aucun style. Nous ne montrons pas de versions interactives des cinq autres bibliothèques, afin que rien ici n'imite leur apparence.

Bouton

La plupart des bibliothèques fournissent un bouton avec des variantes. Remarquez que Radix et Headless UI vous laissent l'apparence, tandis que daisyUI exprime les variantes sous forme de classes et les autres sous forme de props.

Bouton : 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>

Bouton : 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} />;
}

Bouton : 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>

Bouton : 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>

Bouton : 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>

Bouton : 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>

Dialogue (modale)

C'est dans le dialogue que se cache le travail d'accessibilité : piège à focus, fermeture avec Escape, retour du focus au déclencheur, étiquetage. Les bibliothèques headless et MUI le font en JavaScript ; daisyUI s'appuie sur l'élément natif <dialog>, qui gère Escape et le focus dans le navigateur.

Dialogue (modale) : 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>

Dialogue (modale) : 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>

Dialogue (modale) : 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>

Dialogue (modale) : 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>

Dialogue (modale) : 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>

Dialogue (modale) : 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>

Menu déroulant

Les menus ont besoin de la navigation aux flèches, de la recherche par saisie et de rôles corrects. Radix, Headless UI, shadcn/ui et MUI s'en chargent ; la version <details> de daisyUI s'ouvre et se ferme sans JavaScript mais n'ajoute pas la navigation aux flèches.

Menu déroulant : 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>

Menu déroulant : 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>

Menu déroulant : 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>

Menu déroulant : 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>

Menu déroulant : 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>

Menu déroulant : 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>

Onglets

Des onglets corrects exigent role="tablist", role="tab", aria-selected et le passage d'un onglet à l'autre avec les flèches. Dans daisyUI et MUI, vous reliez vous-même les panneaux et les ID ; les autres le font pour vous.

Onglets : 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>

Onglets : 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>

Onglets : 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>

Onglets : 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>

Onglets : 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>

Onglets : 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>

Interrupteur (toggle)

Un interrupteur est une commande marche/arrêt annoncée comme role="switch". daisyUI stylise une vraie case à cocher, ce qui conserve le comportement natif des formulaires ; les autres produisent un bouton avec le rôle switch.

Interrupteur (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>

Interrupteur (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>

Interrupteur (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>

Interrupteur (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>

Interrupteur (toggle) : Flowbite React

import { ToggleSwitch } from "flowbite-react";

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

Interrupteur (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 (notification)

C'est sur les toasts que les bibliothèques diffèrent le plus. Certaines vous donnent un composant que vous pilotez avec un état, d'autres une fonction à appeler de n'importe où, et Headless UI n'en propose pas du tout.

Toast (notification) : 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 (notification) : 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 (notification) : 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 (notification) : 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 (notification) : 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 (notification) : 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>}
/>

Lequel choisir selon le type de projet

ProjetBon choixPourquoi
Site vitrine ou landing page en TailwinddaisyUI, ou Tailwind seulDes pages surtout statiques ont besoin de boutons, de cartes et d'un menu, pas d'une couche de composants JavaScript. Les classes de daisyUI fonctionnent aussi dans des pages sans React.
Produit SaaS avec sa propre identitéshadcn/ui, ou Radix / Headless UI stylés par vos soinsVous obtenez un comportement accessible sans hériter de l'apparence d'un autre produit, et vous pouvez coller exactement à votre design system.
Créer votre propre design system ou bibliothèque de composantsRadix Primitives (ou Base UI), Headless UIDes primitives sans style sont justement la couche au-dessus de laquelle vous voulez maîtriser les styles. shadcn/ui est lui-même un exemple de cette approche.
Outil interne, back-office, tableau de bordMUI, ou shadcn/uiL'étendue de MUI (tableaux, sélecteurs de date via MUI X, formulaires) fait gagner le plus de temps quand livrer compte plus que l'apparence. shadcn/ui si vous utilisez déjà Tailwind.
Prototype ou hackathon sous TailwindFlowbite React ou daisyUIDes composants à l'aspect fini avec très peu de travail de style. Prévoyez de revoir ce choix si le prototype devient un produit.
Équipe qui utilise déjà Material Design (ou une interface de style Android)MUIIl implémente directement Material Design, si bien que designers et développeurs partagent le même vocabulaire.
Exigences d'accessibilité strictes (secteur public, grandes entreprises)Radix Primitives, Headless UI, MUI, ou shadcn/ui sur ces basesLe comportement au clavier et la gestion du focus sont intégrés et documentés. Quel que soit votre choix, testez quand même au clavier et avec un lecteur d'écran ; aucune bibliothèque ne rend une page accessible à elle seule.

Questions à trancher avant de choisir

Pour les hooks sur lesquels reposent ces composants, consultez l'aide-mémoire des hooks React. Pour les classes utilitaires utilisées dans les extraits, voyez l'aide-mémoire Tailwind, et pour les états hover, focus et désactivé dont chaque bouton a besoin, les états de bouton en CSS. Vous pouvez aussi parcourir dans notre galerie de composants des modales, des boutons et des éléments de navigation React et Tailwind prêts à l'emploi.

Sources

Vérifié en octobre 2026 : la documentation et le changelog de shadcn/ui (ui.shadcn.com), le dépôt GitHub shadcn-ui/ui ; la documentation de Radix Primitives, y compris sa présentation de l'accessibilité (radix-ui.com/primitives) ; Headless UI (headlessui.com) ; les pages d'installation, de mise à niveau et de composants de daisyUI (daisyui.com) ; la documentation de MUI Material UI (mui.com) ; et les fiches du registre npm de shadcn, radix-ui, @headlessui/react, daisyui, flowbite-react et @mui/material pour les versions, les licences et les peer dependencies.

Questions fréquentes

shadcn/ui est-il une bibliothèque de composants ?

Pas au sens habituel. Sa propre documentation explique que ce n'est pas une bibliothèque de composants mais une façon de construire la vôtre : une CLI copie le code source des composants dans votre projet, et c'est vous qui modifiez et maintenez ce code. Ses parties interactives reposent sur une bibliothèque headless, Base UI par défaut pour les nouveaux projets depuis juillet 2026, Radix restant pris en charge.

Quelle différence entre Radix et Headless UI ?

Les deux sont des composants React accessibles et sans style. Radix Primitives propose un ensemble plus large, avec notamment toast, tooltip, slider et toolbar, et prend en charge React 16.8 à 19. Headless UI vient de l'équipe de Tailwind CSS, propose un ensemble plus restreint sans toast ni tooltip, et exige React 18 ou 19.

daisyUI fonctionne-t-il avec React ?

Oui. daisyUI est un plugin Tailwind CSS qui ajoute des noms de classes comme btn, modal et tabs, que vous utilisez en JSX comme n'importe quelle autre classe Tailwind. Il ne fournit pas de composants React, donc l'état, comme l'ouverture d'une modale ou le changement d'onglet, est géré dans votre propre code React.

Ces bibliothèques sont-elles gratuites pour un usage commercial ?

Oui. shadcn/ui, Radix Primitives, Headless UI, daisyUI, flowbite-react et le paquet principal Material UI de MUI sont tous sous licence MIT au moment de la rédaction (octobre 2026). Les composants MUI X Pro et Premium et les blocs Pro de Flowbite sont des produits commerciaux distincts.

Quelle bibliothèque UI React est la meilleure pour l'accessibilité ?

Radix Primitives, Headless UI et MUI intègrent la navigation au clavier et la gestion du focus dans leurs composants, et shadcn/ui en hérite par sa couche de primitives. daisyUI s'appuie sur les éléments HTML natifs, donc vous ajoutez vous-même ARIA et le comportement clavier. Quel que soit votre choix, testez au clavier et avec un lecteur d'écran.

Peut-on utiliser MUI avec Tailwind CSS ?

Oui, mais ils stylent différemment : MUI utilise Emotion et un thème JavaScript, Tailwind des classes utilitaires. Ils fonctionnent côte à côte, mais vous devez synchroniser vous-même les couleurs et les espacements entre les deux thèmes. Les équipes qui veulent tout en Tailwind choisissent plutôt shadcn/ui ou une bibliothèque headless.

En direct : Radix Primitives {title} (bibliothèque sans style, nos classes Tailwind)

Modifier le profil

Appuyez sur Tab : le focus reste à l'intérieur. Appuyez sur Escape ou cliquez à l'extérieur pour fermer.

Nom affiché

Annuler

Enregistrer

Fermer

rien pour l'instant

Options

Renommer

Dupliquer

Déplacer (désactivé)

Afficher les fichiers masqués

Essayez les flèches et la recherche par saisie. Dernier choix : {last}

Paramètres

Compte

Facturation

Équipe

Panneau des paramètres du compte. Utilisez les flèches gauche et droite sur les onglets.

Panneau Facturation.

Panneau Équipe.

Notifications par e-mail : activées

Notifications par e-mail : désactivées

Enregistrer les modifications

Modifications enregistrées

Enregistré {n} fois dans cette démo.

Enregistré {n} fois dans cette démo.

Annuler l'enregistrement

Annuler

Commencer gratuitement · Sans carte bancaire

Voir aussi: Guides

Produit

Pour qui

Fonctionnalités

Ressources

Entreprise

Plan du site