Librerie di Componenti UI React a Confronto: shadcn/ui, Radix, Headless UI, daisyUI, Flowbite e MUI

shadcn/ui, Radix, Headless UI, daisyUI, Flowbite e MUI differiscono soprattutto nello stile: Radix e Headless UI sono senza stile, daisyUI e Flowbite sono Tailwind già stilizzato, MUI è Material Design e shadcn/ui copia codice già stilizzato nel tuo progetto. Ecco gli stessi sei componenti in ognuna, più quale scegliere.

In breve

Queste sei librerie risolvono problemi diversi, ed è per questo che alla domanda "qual è la migliore" non esiste una risposta unica. Due di esse (Radix Primitives e Headless UI) ti danno comportamento e accessibilità senza alcuno stile. Due (daisyUI e Flowbite) ti danno un aspetto Tailwind già rifinito. MUI ti dà un design system completo con un proprio motore di stile. shadcn/ui non è affatto un pacchetto: copia nel tuo progetto il sorgente di componenti già stilizzati, costruiti sopra un livello headless.

Tutti i dati qui sotto (versioni, licenze, requisiti) sono stati verificati sulla documentazione ufficiale, sul repository GitHub e sulla scheda npm di ciascun progetto a ottobre 2026. Le versioni cambiano in fretta, quindi considera i numeri validi "al momento della stesura".

Tabella di confronto

shadcn/uiRadix PrimitivesHeadless UIdaisyUIFlowbite ReactMUI (Material UI)
Cosa installiuna CLI che copia il sorgente dei componenti nel tuo repositorypacchetti npm (radix-ui o uno per componente)@headlessui/reactplugin Tailwind daisyuiflowbite-react@mui/material più Emotion
Modello di stileclassi Tailwind in codice che possiedi; tema tramite variabili CSSsenza stile; aggiungi tu le classi, stato tramite attributi data-statesenza stile; stato tramite attributi data-*, pensato per Tailwindclassi CSS di componente (btn, modal) e temicomponenti Tailwind già stilizzati, personalizzabili con temiMaterial Design, CSS-in-JS (prop sx, oggetto theme)
Versione (ottobre 2026)CLI shadcn 4.x (nessun pacchetto runtime)radix-ui 1.8; pacchetti singoli 1.x e 2.x2.25.x0.12 (prima della 1.0)9.x
LicenzaMITMITMITMITMITMIT (MUI X Pro/Premium a pagamento sono separati)
React richiestosìda 16.8 a 1918 o 19no (semplice HTML e CSS)18 o 1917, 18 o 19
Tailwind richiestosì (v4 nella documentazione attuale)nono, ma è pensato per Tailwindsì, Tailwind 4 per daisyUI 5sì, Tailwind 3 o 4no
Approccio all'accessibilitàla eredita dal suo livello di primitive (Base UI o Radix)segue le WAI-ARIA Authoring Practices; tastiera e focus integratidescritto come "fully accessible"; tastiera e focus integratisi basa su elementi nativi (<dialog>, <details>); ARIA e comportamento li aggiungi tucomponenti React con posizionamento tramite Floating UI; verifica tu l'uso da tastieragestione di ARIA e tastiera per ogni componente, documentata componente per componente
Ha un toastsì, tramite Sonnersì (Toast)nosì (solo classe di layout)sì (Toast)sì (Snackbar)

Abbiamo escluso di proposito la dimensione del bundle dalla tabella. I numeri dipendono molto da quali componenti importi, dal fatto che il tuo bundler li elimini con il tree-shaking e (per daisyUI) da quanto CSS Tailwind genera per le classi che usi. Un unico valore in "kB" per libreria sarebbe più fuorviante che utile. Misura la tua build: esegui l'analyzer del tuo bundler prima e dopo aver aggiunto i componenti che ti servono davvero.

Ogni libreria nel dettaglio

shadcn/ui

Cos'è. shadcn/ui si descrive come "not a component library" ma "how you build your component library", cioè non una libreria di componenti ma il modo in cui costruisci la tua. Esegui la sua CLI (npx shadcn init, poi npx shadcn add button) e questa scrive il sorgente del componente nel tuo progetto. Da quel momento il codice è tuo da modificare; non c'è alcun pacchetto runtime di shadcn da aggiornare.

Stile. Classi Tailwind CSS dentro i file copiati, con colori e raggi come variabili CSS così puoi cambiare tema in un solo punto. Le varianti di solito sono definite con class-variance-authority.

Sotto il cofano. Le parti interattive poggiano su una libreria headless. Secondo il changelog di shadcn/ui, da luglio 2026 i nuovi progetti usano Base UI come impostazione predefinita, e Radix "is not being deprecated", cioè non viene deprecato: sono supportati entrambi. Il suo toast è costruito su Sonner, un pacchetto open source separato per i toast.

Licenza e versione. MIT (repository GitHub shadcn-ui/ui). Il pacchetto CLI shadcn era alla 4.x su npm al momento della stesura.

Attenzione a. Siccome il codice è tuo, è tua anche la manutenzione. Le correzioni a monte non arrivano automaticamente nelle tue copie, e progetti diversi si allontanano tra loro col tempo.

Radix Primitives

Cos'è. Un insieme di componenti React accessibili e senza stile (dialog, menu a tendina, tab, switch, toast, tooltip, popover e altri). Puoi installare tutto dal singolo pacchetto radix-ui (1.8 al momento della stesura) oppure un pacchetto per componente, come @radix-ui/react-dialog.

Stile. Nessuno di default. Ogni parte rende un semplice elemento che puoi stilizzare con qualsiasi metodo. Lo stato è esposto tramite attributi data, per esempio data-state="open" o data-highlighted, che si abbinano bene alle varianti data-[state=open]: di Tailwind.

Accessibilità. La documentazione di Radix dice che le primitive seguono le WAI-ARIA Authoring Practices, offrono il supporto da tastiera e gestiscono il focus (per esempio, intrappolando il focus dentro un dialog aperto e restituendolo alla chiusura).

Licenza e requisiti. MIT. L'intervallo delle peer dependency npm copre React da 16.8 a 19.

Attenzione a. Scrivi tu ogni stile. Radix non include una primitiva Button: usa un <button> nativo, oppure l'utility Slot per unire le props al tuo elemento.

Headless UI

Cos'è. Componenti senza stile del team di Tailwind CSS. Il pacchetto React, @headlessui/react (2.2 al momento della stesura), include Button, Checkbox, Combobox, Dialog, Disclosure, Fieldset, Input, Listbox, Menu (menu a tendina), Popover, Radio Group, Select, Switch, Tabs, Textarea e Transition.

Stile. Senza stile. I componenti espongono lo stato tramite attributi data (data-open, data-checked, data-selected, data-focus), quindi li stilizzi con varianti Tailwind come data-checked:bg-blue-600 (sintassi di Tailwind 4) o data-[checked]:bg-blue-600 (Tailwind 3).

Accessibilità. Il suo sito descrive i componenti come "completely unstyled, fully accessible", cioè del tutto privi di stile e pienamente accessibili. Navigazione da tastiera, focus intrappolato nei dialog e collegamenti ARIA sono integrati.

Licenza e requisiti. MIT. React 18 o 19 (peer dependency npm).

Attenzione a. L'insieme è più piccolo di quello di Radix: non ci sono toast, tooltip o slider, quindi per quelli ti servirà un altro pacchetto.

daisyUI

Cos'è. Un plugin di Tailwind CSS che aggiunge nomi di classe di componente come btn, modal, dropdown, tabs, toggle e toast, più una serie di temi di colore. Fornisce CSS, non componenti React, quindi funziona con qualsiasi framework o anche senza.

Stile. Classi semantiche con modificatori (btn btn-primary btn-sm) che puoi comunque combinare con le normali utility Tailwind. I temi si cambiano tramite variabili CSS.

Requisiti. daisyUI 5 (uscito per la prima volta a febbraio 2025, 5.x al momento della stesura) è pensato per Tailwind CSS 4; la sua guida all'aggiornamento ti fa aggiornare prima Tailwind. Si installa con una sola riga @plugin "daisyui"; nel tuo CSS.

Accessibilità. Essendo solo CSS, il comportamento viene dall'HTML nativo: il modale usa l'elemento <dialog> (Escape lo chiude e il browser gestisce il focus), i menu a tendina usano <details> o la popover API. Tutto il resto (ARIA per le tab, annuncio dei toast) spetta a te.

Licenza. MIT.

Attenzione a. In React gestisci tu lo stato (per esempio chiamando showModal() tramite un ref). Non c'è gestione dei tasti freccia per menu o tab, a meno che non la aggiunga tu.

Flowbite React

Cos'è. Componenti React (flowbite-react) stilizzati con Tailwind, del progetto Flowbite. Include Button, Modal, Dropdown, Tabs, ToggleSwitch, Toast, Navbar, Sidebar, Datepicker e altri.

Stile. Già stilizzati con classi Tailwind, personalizzabili tramite un oggetto theme e una prop theme su ogni componente.

Requisiti e versione. Versione 0.12 al momento della stesura: non ha ancora raggiunto la 1.0, quindi aspettati breaking change tra versioni minori. Le peer dependency npm sono React 18 o 19 e Tailwind CSS 3 o 4. Usa Floating UI per posizionare menu a tendina e tooltip.

Accessibilità. I componenti rendono i ruoli attesi per i pattern comuni, ma non abbiamo trovato una dichiarazione di accessibilità pubblicata paragonabile a quella di Radix. Verifica il comportamento con tastiera e screen reader per i componenti su cui fai affidamento.

Licenza. MIT (la libreria open source; Flowbite vende anche blocchi Pro e file di design separati).

MUI (Material UI)

Cos'è. Con le sue parole, "an open-source React component library that implements Google's Material Design", cioè una libreria open source di componenti React che implementa il Material Design di Google. È l'insieme più ampio di questo confronto, con componenti per visualizzazione dati, input, navigazione, layout e feedback.

Stile. CSS-in-JS. Di default usa Emotion (@emotion/react e @emotion/styled sono peer dependency di @mui/material 9). Lo personalizzi con createTheme e stilizzi i casi singoli con la prop sx. Può convivere con Tailwind, ma i due sistemi di temi non condividono token a meno che non li colleghi tu.

Versione e licenza. Versione 9 (la 9.0.0 è stata pubblicata ad aprile 2026). La libreria di base è MIT. Le funzioni avanzate di data grid, date e grafici in MUI X Pro e Premium sono licenze commerciali.

Accessibilità. I componenti includono attributi ARIA e gestione della tastiera, e le pagine dei componenti nella documentazione di MUI descrivono il comportamento di accessibilità componente per componente.

Attenzione a. Allontanarsi dall'aspetto Material richiede un vero lavoro sul tema, e il CSS-in-JS richiede configurazione aggiuntiva con i React Server Components.

Gli stessi sei componenti in ogni libreria

Qui sotto, lo stesso pulsante, dialog, menu a tendina, tab, switch e toast sono scritti sei volte, una per ciascuna libreria secondo la sua API documentata. Ogni snippet è codice originale scritto per questa pagina (non copiato dalla documentazione delle librerie), usa la versione major attuale di ciascuna libreria ed è ridotto alle parti che cambiano. Le versioni dal vivo e cliccabili sono mostrate solo per Radix Primitives, perché Radix è la libreria installata su questo sito. Sono stilizzate con le nostre classi Tailwind, dato che Radix non include stili. Non mostriamo versioni dal vivo delle altre cinque librerie, quindi nulla qui imita il loro aspetto.

Pulsante

La maggior parte delle librerie include un pulsante con varianti. Nota come Radix e Headless UI lascino a te l'aspetto, mentre daisyUI esprime le varianti come classi e le altre come props.

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

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

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

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

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

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

Un dialog è il punto in cui si nasconde il lavoro sull'accessibilità: focus intrappolato, Escape per chiudere, focus restituito all'elemento che l'ha aperto, etichette. Le librerie headless e MUI lo fanno in JavaScript; daisyUI si appoggia all'elemento nativo <dialog>, che gestisce Escape e focus nel browser.

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

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

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

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

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

Dialog (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 a tendina

I menu richiedono navigazione con i tasti freccia, ricerca durante la digitazione e ruoli corretti. Radix, Headless UI, shadcn/ui e MUI lo gestiscono; la versione con <details> di daisyUI si apre e si chiude senza JavaScript ma non aggiunge la navigazione con i tasti freccia.

Menu a tendina: 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 a tendina: 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 a tendina: 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 a tendina: 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 a tendina: 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 a tendina: 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>

Tab

Tab corrette richiedono role="tablist", role="tab", aria-selected e lo spostamento tra le tab con i tasti freccia. In daisyUI e MUI colleghi tu pannelli e ID; le altre li collegano per te.

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

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

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

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

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

Tab: 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 (interruttore)

Uno switch è un controllo acceso/spento annunciato come role="switch". daisyUI stilizza una vera checkbox, che mantiene il comportamento nativo dei form; le altre rendono un pulsante con il ruolo switch.

Switch (interruttore): 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 (interruttore): 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 (interruttore): 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 (interruttore): 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 (interruttore): Flowbite React

import { ToggleSwitch } from "flowbite-react";

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

Switch (interruttore): 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 (notifica)

I toast sono l'ambito in cui le librerie differiscono di più. Alcune ti danno un componente da controllare con lo stato, altre una funzione da chiamare ovunque, e Headless UI lo esclude del tutto.

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

Quale scegliere in base al tipo di progetto

ProgettoScelta adattaPerché
Sito di marketing o landing page in TailwinddaisyUI, o Tailwind puroPagine per lo più statiche hanno bisogno di pulsanti, card e un menu, non di un livello di componenti JavaScript. Le classi di daisyUI funzionano anche in pagine non React.
Prodotto SaaS con un brand proprioshadcn/ui, o Radix / Headless UI stilizzati da teOttieni un comportamento accessibile senza ereditare l'aspetto di un altro prodotto, e puoi allinearti esattamente al tuo design system.
Costruire il tuo design system o la tua libreria di componentiRadix Primitives (o Base UI), Headless UILe primitive senza stile sono il livello sopra cui vuoi possedere gli stili. shadcn/ui stesso è un esempio di questo approccio.
Strumento interno, pannello di amministrazione, dashboardMUI, o shadcn/uiL'ampiezza di MUI (tabelle, selettori di date tramite MUI X, form) fa risparmiare più tempo quando l'aspetto conta meno del rilascio. shadcn/ui se usi già Tailwind.
Prototipo o hackathon con TailwindFlowbite React o daisyUIComponenti dall'aspetto finito con pochissimo lavoro di stile. Metti in conto di rivederli se il prototipo diventa un prodotto.
Team che usa già il Material Design (o una UI in stile Android)MUIImplementa direttamente il Material Design, quindi designer e sviluppatori condividono un unico vocabolario.
Requisiti di accessibilità rigorosi (pubblica amministrazione, enterprise)Radix Primitives, Headless UI, MUI, o shadcn/ui basato su di esseIl comportamento di tastiera e focus è integrato e documentato. Qualunque scelta tu faccia, testa comunque con una tastiera e uno screen reader; nessuna libreria rende accessibile una pagina da sola.

Domande da chiarire prima di scegliere

Per gli hook su cui si basano questi componenti, consulta il cheat sheet degli hook di React. Per le classi di utility usate in tutti gli snippet, consulta il cheat sheet di Tailwind, e per gli stati hover, focus e disabled di cui ogni pulsante ha bisogno, gli stati dei pulsanti in CSS. Puoi anche sfogliare modali, pulsanti ed elementi di navigazione pronti in React e Tailwind nella nostra galleria di componenti.

Fonti

Verificate a ottobre 2026: la documentazione e il changelog di shadcn/ui (ui.shadcn.com), il repository GitHub shadcn-ui/ui; la documentazione di Radix Primitives, compresa la panoramica sull'accessibilità (radix-ui.com/primitives); Headless UI (headlessui.com); le pagine di installazione, aggiornamento e componenti di daisyUI (daisyui.com); la documentazione di MUI Material UI (mui.com); e le schede del registro npm di shadcn, radix-ui, @headlessui/react, daisyui, flowbite-react e @mui/material per versioni, licenze e peer dependency.

Domande frequenti

shadcn/ui è una libreria di componenti?

Non nel senso classico. La sua stessa documentazione dice che non è una libreria di componenti ma un modo per costruire la tua: una CLI copia il sorgente dei componenti nel tuo progetto, e sei tu a modificare e mantenere quel codice. Le sue parti interattive sono costruite su una libreria headless, Base UI come impostazione predefinita per i nuovi progetti da luglio 2026, con Radix ancora supportato.

Che differenza c'è tra Radix e Headless UI?

Entrambe offrono componenti React accessibili e senza stile. Radix Primitives ha un insieme più ampio, che include toast, tooltip, slider e toolbar, e supporta React da 16.8 a 19. Headless UI viene dal team di Tailwind CSS, ha un insieme più piccolo senza toast né tooltip e richiede React 18 o 19.

daisyUI funziona con React?

Sì. daisyUI è un plugin di Tailwind CSS che aggiunge nomi di classe come btn, modal e tabs, quindi usi quelle classi in JSX come qualsiasi altra classe Tailwind. Non fornisce componenti React, quindi lo stato, come aprire un modale o cambiare tab, è gestito nel tuo codice React.

Queste librerie sono gratuite per uso commerciale?

Sì. shadcn/ui, Radix Primitives, Headless UI, daisyUI, flowbite-react e il pacchetto principale Material UI di MUI hanno tutti licenza MIT al momento della stesura (ottobre 2026). I componenti MUI X Pro e Premium e i blocchi Pro di Flowbite sono prodotti commerciali separati.

Qual è la migliore libreria UI React per l'accessibilità?

Radix Primitives, Headless UI e MUI integrano nei loro componenti la navigazione da tastiera e la gestione del focus, e shadcn/ui la eredita dal suo livello di primitive. daisyUI si basa su elementi HTML nativi, quindi ARIA e comportamento da tastiera li aggiungi tu. Qualunque usi, testa con una tastiera e uno screen reader.

Posso usare MUI con Tailwind CSS?

Puoi, ma applicano gli stili in modo diverso: MUI usa Emotion e un tema JavaScript, Tailwind usa classi di utility. Funzionano fianco a fianco, anche se devi mantenere tu sincronizzati colori e spaziature tra i due temi. I team che vogliono tutto in Tailwind di solito scelgono invece shadcn/ui o una libreria headless.

Dal vivo: Radix Primitives {title} (libreria senza stile, nostre classi Tailwind)

Modifica profilo

Premi Tab: il focus resta all'interno. Premi Escape o clicca fuori per chiudere.

Nome visualizzato

Annulla

Salva

Chiudi

ancora niente

Opzioni

Rinomina

Duplica

Sposta (disattivato)

Mostra file nascosti

Prova i tasti freccia e la ricerca mentre digiti. Ultima scelta: {last}

Impostazioni

Account

Fatturazione

Team

Pannello delle impostazioni dell'account. Usa le frecce sinistra e destra sulle tab.

Pannello della fatturazione.

Pannello del team.

Notifiche email: attive

Notifiche email: disattivate

Salva modifiche

Modifiche salvate

Salvato {n} volta in questa demo.

Salvato {n} volte in questa demo.

Annulla il salvataggio

Annulla

Inizia gratis · Nessuna carta di credito richiesta

Correlati: Guide

Prodotto

Per chi è

Funzionalità

Risorse

Azienda

Mappa del sito