react-brain
Browse decisions
React & language foundations 3App architecture 11UI 13Platform & native 9Build, test, observe, secure 6AI in React apps 3stack composerdecision recordscensusstaleness benchnewsletterarchitecturechangelogmethodologyroadmap

entriesui · verified 2026-10-01 · react

Component & headless-UI libraries (web)

reviewedconfidence: mediumthis tier holds 71% on the public scorecard (7/20 graded · 0 overturned) →

related decisions: dx · styling · crossplatform

cited by: styling

re-verified 8× — 2026-10-08 · 2026-09-24 · 2026-09-21 · 2026-09-10 · 2026-08-24 · 2026-07-20 +2 · changelog

recommendation

Own-the-code: shadcn/ui (Base UI default since 2026-07; Radix and React Aria also supported) + Tailwind — the default for product teams that want control.

  • max accessibility / headless primitives → React Aria Components, else Base UI
  • want batteries-included + don't want to own styling → MUI (or Mantine / Chakra — same tier)
  • internal admin/enterprise → Ant Design (or MUI)
  • Meta/StyleX-native, agent-ready design system → Astryx (beta at 0.6.x — vet component coverage before betting on it)
  • one design language across web and React Native via shared tokens → HeroUI (separate web + RN libraries; tokens are shared, code is not)
  • agents keep violating your design system (ad-hoc padding, off-theme colors, invented variants) → @shadcn/lint (agent-first linter for Tailwind v4 design systems; shadcn/ui NOT required; runs on ESLint or Oxlint — see note)
  • React Native UI → n/a (this entry is web-only; see RB-E-STYLING / RB-E-CROSSPLATFORM)

Options & tradeoffs

the field considered — and why each one isn’t the default here

optiontradeoffevidence
Base UI (1.x)unstyled accessible primitives (Radix/MUI lineage); render-prop customization. Install as @base-ui/react (1.8.0, 2026-09-04, verified vs npm 2026-09-24) — the old @base-ui-components/react name is deprecated on npm as renamed. See note: BASE UI RENAME
React Aria Components (1.x, Adobe)accessibility-first headless primitives; `render` prop pattern (not asChild)5.9M/wk · ships in 1/20
Radix UIunstyled primitives; `asChild` composition; widely used under shadcnships in 7/20
shadcn/uicopy-paste components (own the code) + Tailwind; CLI + registries. Base UI is the DEFAULT headless layer since 2026-07 (4.13); Radix stays supported and React Aria is a third first-class base (`init --base aria`). CLI 4.21.0 (2026-09-04, verified vs npm 2026-09-24). See note: SHADCN
MUI (9) / Chakra (3) / Mantine (9) / Ant Design (6)batteries-included styled systems (majors verified vs npm 2026-09-24); MUI v9 is incrementally adopting Base UI primitives for new components (NumberField, MenuBar), not a full migration
HeroUI (3)React Aria + Tailwind; separate web + RN libraries sharing design tokens (not one cross-platform abstraction)
Astryx (Meta)Meta's open-source design system on React + StyleX: 150+ accessible, themeable components, compile-time atomic styling, agent-ready scaffolding (CLI + MCP); grown 8 yrs internally, 13,000+ Meta apps. Beta: @astryxdesign/core 0.6.x (0.6.0 released 2026-09-10; verified vs the release post + npm 2026-09-24). See note: ASTRYX

evidence: npm weekly downloads (signals snapshot) · “ships in n/D” = adoption across the production-app census, honest denominators

npm weekly downloads (from the corpus's last signals run): react-aria-components 5.9M · antd 4.5M

Verified notes

The split is WHO OWNS THE CODE: headless primitives (Base UI, React Aria, Radix) own behavior and leave styling to you; batteries-included systems (MUI, Chakra, Mantine, Ant, and Meta's StyleX-based Astryx) own both; own-the-code (shadcn/ui) copies the styled component into your repo over a headless layer. shadcn/ui is the product-team default because it puts the hard part (accessible behavior) in a maintained dependency and the opinionated part (markup, styling) where you can change it without forking. The headless layers are converging — Base UI is shadcn's default and MUI v9 is adopting the same primitives — which de-risks the copied-code bet. Web only. SHADCN (verified vs the shadcn changelog): HEADLESS BASES — Base UI became the default component library in shadcn/ui (2026-07-10, 4.13), with Radix explicitly NOT deprecated; React Aria joined as the THIRD first-class base (2026-07-20, `shadcn init --base aria`) with per-base scoped registries and all 8 style variants, so a project standardizes on one base without cross-contamination. 2026-06: chat components and the first headless @shadcn/react package. 2026-08: GitHub registries install from PRIVATE repos too (gh CLI credentials, or GH_TOKEN in CI), so an internal design system can be a registry with zero config. 2026-09: every registry component imports `cn` from the standalone `cn` package instead of a local lib/utils.ts, replacing the copied clsx+tailwind-merge helper projects hand-maintained — same call site, one dependency; `shadcn add` installs it for projects created before the change, and lib/utils.ts survives as a re-export. BASE UI RENAME (2026-09-24, verified vs npm): @base-ui-components/react carries the npm deprecation "Package was renamed to @base-ui/react"; @base-ui/react published 1.0.0 on 2025-12-11 and is at 1.8.0 (2026-09-04) → new installs use @base-ui/react. @SHADCN/LINT (2026-09-21, verified vs the repo + README; npm 0.2.0 of 2026-09-22 verified 2026-09-24): an "agent-first linter for Tailwind design systems" from the shadcn org, 2,240 stars and created 2026-09-02 (as of 2026-09-21). It names a failure the corpus otherwise describes only in prose: a coding agent will add padding to a Button that owns its padding, invent a variant, or reach past the theme, and TypeScript catches none of it. You declare what is allowed in terms of your own components, variants and theme, and a violation produces an error that explains the rule and suggests a fix from what your design system offers — a diagnostic written for a machine to act on. Reachability: it targets TAILWIND V4 projects, does NOT require shadcn/ui, works with React, Svelte and Vue, and ships for BOTH ESLint (9.30+) and Oxlint → it lands in the existing lint lane RB-E-DX reasons about. Young, so it is a when-clause and not a default; the risk is a new rule set, not the idea. ASTRYX (0.6.0, 2026-09-10, verified vs the release post): Meta open-sourced its 8-year internal system (13,000+ apps). 0.6.0 adds RESPONSIVE THEME RULES, a Selector that adapts which surface it presents, a reworked Neutral palette and six templates, and the team describes a specification-backed path toward v1. Still 0.6.x with a documented CLI upgrade step between minors → treat version churn as the cost of adopting early. StyleX itself: RB-E-STYLING.

Canonical reading

Editorial annotations on why each piece matters — the articles themselves are the originals; read them there.

Building an LLM-safe design systemPolar

Argues a design system should become the only expressible decisions for LLM-authored code — token-only props, a polymorphic Box, StyleX compile-time enforcement. A durable take on component libraries in the AI-coding era.

Props Are Not a Design Systemvitonsky

Constrain component APIs to SEMANTIC choices, not stylistic ones: `<Button variant="primary" size="xl">` over `<Button radius="xl" fontSize="xl" fontWeight={500}>`. A variant is the observable unit of a design system — you can see exactly which ones exist and update them all at once; arbitrary style props can't be enumerated or audited. Modifiers stay first-class API, not an escape hatch: stacking many modifiers on one call site is the signal to cut a new variant instead. Framework-agnostic (works with BEM, CSS Modules, Chakra recipes) — the same discipline the LLM-safe-design-system reading argues for, from the opposite direction (enumerable surface, not token-only props).

Building design components with action props using async ReactAurora Scharff

A pattern for design-system components that accept action props and run them in internal transitions (useTransition/useOptimistic) for built-in pending/optimistic UI. A durable component-API pattern for the async-React era.

Sources

Depth (in-domain rules) is owned by the design-system skill — this entry is selection breadth.

The full explanation

The reviewed long-form essay behind this entry — the why, not a how-to. Also on GitHub.

About component & headless-UI libraries — who owns the code

Diataxis: Explanation. This page builds understanding of the web component-library landscape — the reasoning behind the picks. It is not a component catalog. Token/theming/a11y governance is owned by design-system; styling engines by RB-E-STYLING. This entry is web-only — React Native UI routes to RB-E-STYLING/RB-E-CROSSPLATFORM.

The one question that organises everything: who owns the code you'll be debugging in a year?

Every component library answers three needs — behavior (focus traps, keyboard interaction, ARIA), styling, and maintenance — and the durable axis is who owns each:

  • Headless primitives (Base UI, Radix, React Aria): the library owns behavior, you own styling. Maximum control, maximum styling work.
  • Batteries-included systems (MUI, Mantine, Chakra, Ant, Astryx): the library owns behavior and styling. Fastest start, hardest to make yours.
  • Own-the-code (shadcn/ui): the styled component is copied into your repo over a headless layer. You own everything visible; upstream owns only the invisible behavior underneath.

This is why "which component library" arguments talk past each other — they're usually arguments about which ownership split a team can live with.

The default, and why

Own-the-code: shadcn/ui (Base UI default since 2026-07; Radix and React Aria also supported) + Tailwind — the default for product teams that want control.

shadcn's model wins for product teams because it puts the hard part (accessible behavior) in a maintained dependency and the opinionated part (markup, styling) in your repo where you can change it without forking anything. The 2026 shift underneath it matters: Base UI became shadcn's default headless layer (Radix explicitly not deprecated — every component ships for both), and MUI v9 is incrementally adopting the same primitives. The Radix/MUI lineages are converging on one behavior layer, which de-risks the whole own-the-code bet: the primitives under your copied components are becoming the ecosystem's shared foundation rather than one vendor's.

The landscape, by ownership split

Base UI / Radix / React Aria Components — the headless tier. Base UI is the convergence point (Radix/MUI lineage); React Aria is Adobe's accessibility-first take with the strongest interaction rigor and its own render-prop composition style. Pick one directly when you're building a design system, not assembling an app.

shadcn/ui — the own-the-code layer over that tier: CLI + registries, chat components (2026-06), and a first headless @shadcn/react package (tested behavior as a dependency while styling stays copy-paste). Since 2026-07-20 React Aria is a third first-class base (shadcn init --base aria) beside Base UI (the default) and Radix, with per-base scoped registries.

Current facts (verified vs npm 2026-09-24). Base UI now installs as @base-ui/react; the old @base-ui-components/react name is deprecated on npm as renamed. When agents keep breaking the design system, @shadcn/lint (Tailwind v4 projects; shadcn/ui not required; ESLint or Oxlint) turns those violations into lint errors written for the agent to fix.

MUI / Mantine / Chakra / Ant Design — batteries-included. The right call when shipping speed beats visual identity: internal tools, admin surfaces, enterprise CRUD. Ant for that enterprise idiom specifically.

Astryx (Meta, beta) — batteries-included with a twist: StyleX compile-time styling (RB-E-STYLING) and agent-ready scaffolding (CLI + MCP), open-sourced from 8 years of internal use. Vet component coverage before betting; it's the most credible new batteries-included entrant in years.

HeroUI — React Aria + Tailwind, with separate web and RN libraries sharing tokens — a reminder that "cross-platform component library" today means shared tokens, not shared code.

Tradeoffs and failure modes to name out loud

  • Copy-paste is a fork you maintain. shadcn components don't auto-upgrade; behavior fixes arrive via the headless dep, but markup/styling drift is yours. Budget for it.
  • Fighting a batteries-included theme. If you're overriding MUI styles everywhere, you wanted the headless tier — the override layer becomes its own design system, minus the coherence.
  • Mixing headless layers. Radix here, React Aria there, Base UI in the new code — three composition models and three focus-management philosophies in one app. Converge deliberately.
  • The AI-era failure mode: agent-written UI that reaches past the design system's props into raw divs. The LLM-safe-design-system reading argues the fix — make the system's tokens/props the only expressible decisions — and it's why agent-scaffolding (Astryx MCP, shadcn registries) is becoming a selection criterion at all (RB-E-AI-DEVTOOLS).
  • Accessibility assumed, not verified. Headless ≠ accessible-by-default once you restyle; interaction contracts survive, contrast and affordance don't (RB-E-A11Y).

How it interacts with the rest of the stack

  • Styling (RB-E-STYLING). shadcn assumes Tailwind; Astryx assumes StyleX — the component layer and the styling engine are one decision wearing two names.
  • A11y (RB-E-A11Y). The headless tier exists because accessible behavior is the hardest part to hand-roll; that's the part you should never own.
  • AI dev tooling (RB-E-AI-DEVTOOLS). Registries/MCP scaffolding determine how well agents generate on-system UI — a new axis this decade added to an old decision.
  • Cross-platform (RB-E-CROSSPLATFORM). None of this transfers to RN; shared design happens at the token level (HeroUI's split is the honest model).

In one paragraph

Choose a component library by who owns which layer: headless primitives (behavior theirs, styling yours), batteries-included (both theirs), or own-the-code (behavior theirs, everything visible copied into your repo). The product-team default is shadcn/ui + Tailwind, now riding Base UI as its default headless layer — the Radix/MUI lineages converging on one shared behavior foundation makes the copied-code bet safer, not riskier. Go batteries-included (MUI/ Mantine/Ant, or Meta's agent-ready Astryx) when shipping speed beats visual identity, and drop to the headless tier directly when you're building a design system. Whatever you pick, never hand-roll the behavior layer — that's the part with the accessibility landmines.


See also: RB-E-STYLING (the engine under the components), RB-E-A11Y (what headless does and doesn't guarantee), RB-E-AI-DEVTOOLS (agent scaffolding as a selection axis). Token/theming/ lifecycle governance: the design-system skill.

Related in ui: styling · animation · lists · a11y · i18n · charts · editors · svg · maps · calendars · sheets · polish