shadcn/ui, Radix, Headless UI, daisyUI, Flowbite e MUI diferem principalmente no estilo: Radix e Headless UI não têm estilo, daisyUI e Flowbite são Tailwind pré-estilizado, o MUI é Material Design e o shadcn/ui copia código estilizado para o seu projeto. Aqui estão os mesmos seis componentes em cada uma, e qual escolher.
Essas seis bibliotecas resolvem problemas diferentes, e é por isso que a pergunta "qual é a melhor" não tem uma resposta única. Duas delas (Radix Primitives e Headless UI) entregam comportamento e acessibilidade sem nenhum estilo. Duas (daisyUI e Flowbite) entregam um visual Tailwind pronto. O MUI entrega um design system completo, com o próprio motor de estilos. O shadcn/ui nem é um pacote: ele copia para o seu projeto o código-fonte de componentes já estilizados, construídos sobre uma camada headless.
Todos os fatos abaixo (versões, licenças, requisitos) foram conferidos na documentação oficial, no repositório do GitHub e na página do npm de cada projeto em outubro de 2026. As versões mudam rápido, então considere os números como "no momento em que este texto foi escrito".
| shadcn/ui | Radix Primitives | Headless UI | daisyUI | Flowbite React | MUI (Material UI) | |
|---|---|---|---|---|---|---|
| O que você instala | uma CLI que copia o código-fonte dos componentes para o seu repositório | pacotes npm (radix-ui ou um por componente) | @headlessui/react | plugin Tailwind daisyui | flowbite-react | @mui/material mais Emotion |
| Modelo de estilo | classes Tailwind em código que é seu; tema via variáveis CSS | sem estilo; você adiciona as classes, estado via atributos data-state | sem estilo; estado via atributos data-*, pensado para Tailwind | classes CSS de componente (btn, modal) e temas | componentes Tailwind pré-estilizados, com suporte a temas | Material Design, CSS-in-JS (prop sx, objeto de tema) |
| Versão (out. 2026) | CLI shadcn 4.x (sem pacote de runtime) | radix-ui 1.8; pacotes individuais 1.x e 2.x | 2.2 | 5.x | 0.12 (pre-1.0) | 9.x |
| Licença | MIT | MIT | MIT | MIT | MIT | MIT (os pagos MUI X Pro/Premium são à parte) |
| Exige React | sim | 16.8 a 19 | 18 ou 19 | não (HTML e CSS puros) | 18 ou 19 | 17, 18 ou 19 |
| Exige Tailwind | sim (v4 na documentação atual) | não | não, mas foi feito para ele | sim, Tailwind 4 para o daisyUI 5 | sim, Tailwind 3 ou 4 | não |
| Abordagem de acessibilidade | herda da sua camada de primitivos (Base UI ou Radix) | segue as WAI-ARIA Authoring Practices; teclado e foco já incluídos | descrito como "totalmente acessível"; teclado e foco já incluídos | depende de elementos nativos (<dialog>, <details>); você adiciona ARIA e comportamento | componentes React com posicionamento via Floating UI; teste o uso por teclado você mesmo | ARIA e suporte a teclado em cada componente, documentados componente a componente |
| Tem toast | sim, via Sonner | sim (Toast) | não | sim (só a classe de layout) | sim (Toast) | sim (Snackbar) |
Deixamos o tamanho do bundle fora da tabela de propósito. Os números dependem muito de quais componentes você importa, de o seu bundler fazer tree-shaking deles ou não e (no caso do daisyUI) de quanto CSS o Tailwind gera para as classes que você usa. Um único número em "kB" por biblioteca mais confundiria do que ajudaria. Meça o seu próprio build: rode o analisador do seu bundler antes e depois de adicionar os componentes de que você realmente precisa.
O que é. O shadcn/ui se descreve como "não uma biblioteca de componentes", e sim "como você constrói a sua biblioteca de componentes". Você roda a CLI dele (npx shadcn init, depois npx shadcn add button) e ela escreve o código-fonte do componente no seu projeto. A partir daí o código é seu para editar; não existe pacote de runtime do shadcn para atualizar.
Estilo. Classes do Tailwind CSS dentro dos arquivos copiados, com cores e raios como variáveis CSS, para que você troque o tema em um só lugar. As variantes costumam ser definidas com class-variance-authority.
Por baixo dos panos. As partes interativas ficam sobre uma biblioteca headless. Segundo o changelog do shadcn/ui, desde julho de 2026 os projetos novos usam Base UI por padrão, e o Radix "não está sendo descontinuado": os dois são suportados. O toast dele é feito com o Sonner, um pacote de toast open source separado.
Licença e versão. MIT (repositório do GitHub shadcn-ui/ui). O pacote da CLI, shadcn, estava na 4.x no npm no momento em que este texto foi escrito.
Atenção. Como o código é seu, a manutenção também é. Correções feitas na origem não chegam automaticamente às suas cópias, e projetos diferentes vão se distanciando com o tempo.
O que é. Um conjunto de componentes React acessíveis e sem estilo (dialog, menu suspenso, abas, switch, toast, tooltip, popover e outros). Você pode instalar tudo pelo pacote único radix-ui (1.8 no momento em que este texto foi escrito) ou um pacote por componente, como @radix-ui/react-dialog.
Estilo. Nenhum por padrão. Cada parte renderiza um elemento simples que você pode estilizar com qualquer método. O estado é exposto como atributos data, por exemplo data-state="open" ou data-highlighted, que combinam bem com as variantes data-[state=open]: do Tailwind.
Acessibilidade. A documentação do Radix diz que os primitivos seguem as WAI-ARIA Authoring Practices, oferecem suporte a teclado e gerenciam o foco (por exemplo, prendendo o foco dentro de um diálogo aberto e devolvendo-o ao fechar).
Licença e requisitos. MIT. A faixa de peer dependency no npm cobre do React 16.8 ao 19.
Atenção. Você escreve todos os estilos. O Radix não traz um primitivo Button: use um <button> nativo, ou o utilitário Slot para mesclar props no seu próprio elemento.
O que é. Componentes sem estilo feitos pela equipe do Tailwind CSS. O pacote React, @headlessui/react (2.2 no momento em que este texto foi escrito), inclui Button, Checkbox, Combobox, Dialog, Disclosure, Fieldset, Input, Listbox, Menu (dropdown), Popover, Radio Group, Select, Switch, Tabs, Textarea e Transition.
Estilo. Sem estilo. Os componentes expõem o estado por atributos data (data-open, data-checked, data-selected, data-focus), então você os estiliza com variantes do Tailwind como data-checked:bg-blue-600 (sintaxe do Tailwind 4) ou data-[checked]:bg-blue-600 (Tailwind 3).
Acessibilidade. O site descreve os componentes como "completamente sem estilo, totalmente acessíveis". Navegação por teclado, foco preso nos diálogos e a ligação de ARIA já vêm incluídos.
Licença e requisitos. MIT. React 18 ou 19 (peer dependency no npm).
Atenção. O conjunto é menor que o do Radix: não há toast, tooltip nem slider, então você vai precisar de outro pacote para eles.
O que é. Um plugin do Tailwind CSS que adiciona nomes de classe de componentes como btn, modal, dropdown, tabs, toggle e toast, além de um conjunto de temas de cores. Ele entrega CSS, não componentes React, então funciona com qualquer framework ou sem nenhum.
Estilo. Classes semânticas com modificadores (btn btn-primary btn-sm) que você ainda pode combinar com os utilitários normais do Tailwind. Os temas são trocados por variáveis CSS.
Requisitos. O daisyUI 5 (lançado em fevereiro de 2025, na 5.x no momento em que este texto foi escrito) é feito para o Tailwind CSS 4; o guia de atualização manda atualizar o Tailwind primeiro. Você o instala com uma única linha @plugin "daisyui"; no seu CSS.
Acessibilidade. Como é só CSS, o comportamento vem do HTML nativo: o modal usa o elemento <dialog> (Escape fecha e o navegador cuida do foco), os dropdowns usam <details> ou a API de popover. Qualquer coisa além disso (ARIA nas abas, anúncio dos toasts) fica por sua conta.
Licença. MIT.
Atenção. No React, você mesmo conecta o estado (por exemplo, chamando showModal() por uma ref). Não há suporte às setas do teclado em menus ou abas, a menos que você o adicione.
O que é. Componentes React (flowbite-react) estilizados com Tailwind, do projeto Flowbite. Inclui Button, Modal, Dropdown, Tabs, ToggleSwitch, Toast, Navbar, Sidebar, Datepicker e outros.
Estilo. Pré-estilizados com classes Tailwind, personalizados por um objeto de tema e por uma prop theme em cada componente.
Requisitos e versão. Versão 0.12 no momento em que este texto foi escrito: ainda não chegou à 1.0, então espere mudanças incompatíveis entre versões minor. As peer dependencies no npm são React 18 ou 19 e Tailwind CSS 3 ou 4. Ele usa o Floating UI para posicionar dropdowns e tooltips.
Acessibilidade. Os componentes renderizam os roles esperados para os padrões comuns, mas não encontramos uma declaração de acessibilidade publicada comparável à do Radix. Teste o comportamento com teclado e leitor de tela nos componentes de que você depende.
Licença. MIT (a biblioteca open source; o Flowbite também vende à parte blocos Pro e arquivos de design).
O que é. Nas palavras do próprio projeto, "uma biblioteca open source de componentes React que implementa o Material Design do Google." É o maior conjunto desta comparação, com componentes de exibição de dados, entradas, navegação, layout e feedback.
Estilo. CSS-in-JS. Por padrão usa Emotion (@emotion/react e @emotion/styled são peer dependencies do @mui/material 9). Você define o tema com createTheme e estiliza casos pontuais com a prop sx. Ele pode conviver com o Tailwind, mas os dois sistemas de tema não compartilham tokens, a menos que você os conecte.
Versão e licença. Versão 9 (a 9.0.0 foi publicada em abril de 2026). A biblioteca principal é MIT. Os recursos avançados de data grid, datas e gráficos do MUI X Pro e Premium têm licenças comerciais.
Acessibilidade. Os componentes vêm com atributos ARIA e suporte a teclado, e as páginas de componentes na documentação do MUI descrevem o comportamento de acessibilidade de cada um.
Atenção. Fugir do visual Material exige um trabalho real de tema, e o CSS-in-JS precisa de configuração extra com React Server Components.
Abaixo, o mesmo botão, diálogo, menu suspenso, abas, switch e toast estão escritos seis vezes, uma na API documentada de cada biblioteca. Cada trecho é código original escrito para esta página (não copiado da documentação das bibliotecas), usa a versão major atual de cada biblioteca e foi reduzido às partes que mudam. Versões ao vivo e clicáveis aparecem apenas para o Radix Primitives, porque o Radix é a biblioteca instalada neste site. Elas usam as nossas próprias classes Tailwind, já que o Radix não traz estilos. Não mostramos versões ao vivo das outras cinco bibliotecas, então nada aqui imita o visual delas.
A maioria das bibliotecas traz um botão com variantes. Repare como o Radix e o Headless UI deixam o visual com você, enquanto o daisyUI expressa as variantes como classes e as demais como 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>
O diálogo é onde o trabalho de acessibilidade se esconde: foco preso, Escape para fechar, devolver o foco ao gatilho, rótulos. As bibliotecas headless e o MUI fazem isso em JavaScript; o daisyUI se apoia no elemento nativo <dialog>, que trata o Escape e o foco no navegador.
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>
Menus precisam de navegação pelas setas, busca ao digitar e roles corretos. Radix, Headless UI, shadcn/ui e MUI cuidam disso; a versão do daisyUI com <details> abre e fecha sem JavaScript, mas não adiciona navegação pelas setas.
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>
Abas corretas precisam de role="tablist", role="tab", aria-selected e movimento entre abas pelas setas. No daisyUI e no MUI você mesmo liga os painéis e os IDs; as outras fazem essa ligação por você.
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>
Um switch é um controle de liga/desliga anunciado como role="switch". O daisyUI estiliza um checkbox de verdade, o que mantém o comportamento nativo de formulário; as outras renderizam um botão com o role switch.
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"
/>
É nos toasts que as bibliotecas mais diferem. Algumas dão um componente que você controla com estado, outras dão uma função que você chama de qualquer lugar, e o Headless UI simplesmente não tem.
// 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>}
/>
| Projeto | Boa escolha | Por quê |
|---|---|---|
| Site de marketing ou landing page em Tailwind | daisyUI, ou Tailwind puro | Páginas quase estáticas precisam de botões, cards e um menu, não de uma camada de componentes em JavaScript. As classes do daisyUI também funcionam em páginas sem React. |
| Produto SaaS com marca própria | shadcn/ui, ou Radix / Headless UI estilizados por você | Você ganha comportamento acessível sem herdar o visual de outro produto e consegue seguir o seu design system com exatidão. |
| Construir o seu próprio design system ou biblioteca de componentes | Radix Primitives (ou Base UI), Headless UI | Primitivos sem estilo são a camada sobre a qual você quer ser dono dos estilos. O próprio shadcn/ui é um exemplo dessa abordagem. |
| Ferramenta interna, painel admin, dashboard | MUI, ou shadcn/ui | A amplitude do MUI (tabelas, seletores de data via MUI X, formulários) é o que mais economiza tempo quando entregar importa mais do que o visual. shadcn/ui se você já usa Tailwind. |
| Protótipo ou hackathon em Tailwind | Flowbite React ou daisyUI | Componentes com cara de prontos e pouquíssimo trabalho de estilo. Planeje revisar se o protótipo virar produto. |
| Equipe que já usa Material Design (ou interface no estilo Android) | MUI | Ele implementa o Material Design diretamente, então designers e desenvolvedores compartilham o mesmo vocabulário. |
| Requisitos rígidos de acessibilidade (setor público, grandes empresas) | Radix Primitives, Headless UI, MUI, ou shadcn/ui sobre eles | O comportamento de teclado e foco já vem incluído e documentado. Seja qual for a escolha, teste mesmo assim com teclado e leitor de tela; nenhuma biblioteca torna uma página acessível sozinha. |
Para os hooks em que esses componentes se baseiam, veja a cola de React hooks. Para as classes utilitárias usadas nos trechos, veja a cola de Tailwind e, para os estados de hover, foco e desativado de que todo botão precisa, estados de botão em CSS. Você também pode explorar modais, botões e peças de navegação prontos em React e Tailwind na nossa galeria de componentes.
Conferido em outubro de 2026: a documentação e o changelog do shadcn/ui (ui.shadcn.com), o repositório shadcn-ui/ui no GitHub; a documentação do Radix Primitives, incluindo a visão geral de acessibilidade (radix-ui.com/primitives); Headless UI (headlessui.com); as páginas de instalação, atualização e componentes do daisyUI (daisyui.com); a documentação do MUI Material UI (mui.com); e as páginas do registro npm de shadcn, radix-ui, @headlessui/react, daisyui, flowbite-react e @mui/material para versões, licenças e peer dependencies.
Não no sentido habitual. A própria documentação diz que ele não é uma biblioteca de componentes, e sim uma forma de construir a sua: uma CLI copia o código-fonte dos componentes para o seu projeto, e você edita e mantém esse código. As partes interativas são feitas sobre uma biblioteca headless, Base UI por padrão em projetos novos desde julho de 2026, com o Radix ainda suportado.
Os dois são componentes React acessíveis e sem estilo. O Radix Primitives tem um conjunto maior, incluindo toast, tooltip, slider e toolbar, e suporta do React 16.8 ao 19. O Headless UI vem da equipe do Tailwind CSS, tem um conjunto menor, sem toast nem tooltip, e exige React 18 ou 19.
Sim. O daisyUI é um plugin do Tailwind CSS que adiciona nomes de classe como btn, modal e tabs, então você usa essas classes no JSX como qualquer outra classe do Tailwind. Ele não traz componentes React, então estados como abrir um modal ou trocar de aba ficam no seu próprio código React.
Sim. shadcn/ui, Radix Primitives, Headless UI, daisyUI, flowbite-react e o pacote principal Material UI do MUI têm licença MIT no momento em que este texto foi escrito (outubro de 2026). Os componentes MUI X Pro e Premium e os blocos Pro do Flowbite são produtos comerciais à parte.
Radix Primitives, Headless UI e MUI incluem navegação por teclado e gerenciamento de foco nos componentes, e o shadcn/ui herda isso da sua camada de primitivos. O daisyUI depende de elementos HTML nativos, então você mesmo adiciona ARIA e comportamento de teclado. Seja qual for a escolha, teste com teclado e leitor de tela.
Pode, mas eles estilizam de formas diferentes: o MUI usa Emotion e um tema em JavaScript, o Tailwind usa classes utilitárias. Eles funcionam lado a lado, mas você mesmo precisa manter cores e espaçamentos sincronizados entre os dois temas. Equipes que querem tudo em Tailwind normalmente escolhem o shadcn/ui ou uma biblioteca headless.
Ao vivo: Radix Primitives {title} (biblioteca sem estilo, nossas classes Tailwind)
Editar perfil
Pressione Tab: o foco fica dentro. Pressione Escape ou clique fora para fechar.
Nome de exibição
Cancelar
Salvar
Fechar
nada ainda
Opções
Renomear
Duplicar
Mover (desativado)
Mostrar arquivos ocultos
Experimente as setas e a busca ao digitar. Última escolha: {last}
Configurações
Conta
Cobrança
Equipe
Painel de configurações da conta. Use as setas Left e Right nas abas.
Painel de cobrança.
Painel da equipe.
Notificações por e-mail: ativadas
Notificações por e-mail: desativadas
Salvar alterações
Alterações salvas
Salvo {n} vez nesta demonstração.
Salvo {n} vezes nesta demonstração.
Desfazer o salvamento
Desfazer
Comece grátis · Sem cartão de crédito