Overview & positioning
Radix Primitives is an open-source set of low-level React components for design systems and web applications. The current getting-started path installs the unified radix-ui package, with per-primitive import paths available when teams want narrower entry points. Dialog, Popover, Select, Dropdown Menu, Tooltip and the rest arrive without a visual theme. Radix handles difficult interaction behavior while leaving layout, tokens, typography, animation and brand expression to the application. Its official accessibility guidance documents WAI-ARIA authoring practices, focus management, keyboard navigation and labeling responsibilities, and the WorkOS-maintained repository is MIT-licensed.
shadcn/ui is an open-code component distribution platform rather than a conventional sealed component library. Its CLI initializes a project, installs required dependencies and writes component source into the application's own paths, where the team can change markup, variants and styles directly. The architecture is no longer Radix-only: new projects use Base UI by default, Radix remains fully supported through the radix base, and React Aria is a first-class aria base. The useful comparison is therefore raw Radix primitives versus shadcn/ui's assembled source, registry and CLI workflow; choosing shadcn/ui does not by itself determine which primitive implementation the project uses.
Core capabilities
Radix earns its place by concentrating on behavior that is easy to get subtly wrong. Its primitives cover focus trapping and restoration, keyboard interaction, screen-reader semantics, collision-aware overlays, dismiss behavior, controlled and uncontrolled state, and composable component parts. Because the primitives are unstyled and accept ordinary styling hooks such as className and state data attributes, a team can impose its own DOM conventions and design tokens without first undoing a vendor theme. That makes Radix especially valuable when the component library itself is the product infrastructure and unusual composition requirements matter more than speed to a finished screen.
shadcn/ui earns its place by assembling the layer most product teams would otherwise build repeatedly. It provides styled buttons, forms, dialogs, tables, navigation, command surfaces and larger blocks, with source that can be copied, composed and adapted inside the repository. Accessibility and interaction behavior come from the selected component base rather than from one universal engine: Base UI is the current default, Radix is supported for teams that choose it, and React Aria is another first-class option. The result is faster delivery and direct source ownership, with the trade-off that local customizations and base-specific behavior become part of the application's maintenance surface.
Developer experience & update model
With Radix, the team installs a versioned package and builds its own higher-level component API and visual language around the primitives. Upgrades flow through the package manager, so behavior fixes can be reviewed centrally, while the application's styling remains separate because Radix ships without presentation. That separation is attractive for multi-brand systems and long-lived internal platforms, but it demands more initial engineering: product-ready forms, data displays, navigation patterns, variants, tokens and documentation still have to be designed and implemented. Radix removes much of the interaction and accessibility work; it does not supply the finished design system.
With shadcn/ui, init configures the project and dependencies, while add writes selected components and their dependencies into the codebase. Ownership does not mean dependency-free: the generated component uses its chosen primitive base and supporting packages, and current initialization can add the small build-time shadcn/tailwind.css dependency unless the team runs shadcn eject to inline it. Upstream component changes are not silently forced over local edits. The CLI offers --diff for inspecting registry updates, and the official migration workflow emphasizes reviewing and merging behavior changes because owned source may have been customized. This is more control than a black box, but also more responsibility than bumping one package version.
Pricing, licensing & operational cost
The core code in both compared projects is MIT-licensed. Radix Primitives is open source under the WorkOS copyright, and the shadcn/ui repository carries the MIT license as an open-code distribution project. Neither core project charges a per-seat or usage-metered adoption fee for using this source in an application. That makes the software license price effectively zero for the comparison itself, but it should not be confused with zero dependencies or zero engineering cost. A shadcn/ui project installs the dependencies required by its chosen components, while a Radix project invests engineering time in the styled system built above the primitives.
The meaningful cost difference is the maintenance boundary. Radix centralizes primitive behavior in a versioned dependency and leaves the visual system entirely with the adopting team. shadcn/ui places much more finished UI source inside the application, so the team owns both the freedom to customize and the work of reviewing upstream diffs or migrations. The selected shadcn/ui base also matters operationally: Base UI is now the default, Radix can be pinned explicitly, and React Aria can be selected for its implementation. Procurement is not the differentiator here; staffing, design-system maturity, dependency policy and willingness to maintain copied source are.
Ideal use cases / who should pick which
Pick Radix Primitives when the goal is to author a bespoke design system, enforce a custom DOM and token architecture across several brands, or solve component behavior at the primitive level without inheriting a finished visual layer. It is also the clearer choice when a team specifically wants Radix's APIs and upgrade stream as the shared foundation. If the team instead plans to start with shadcn/ui but still wants Radix underneath, that choice must now be explicit with the Radix base rather than assumed from the shadcn/ui name, because new shadcn/ui projects default to Base UI.
Pick shadcn/ui when the immediate goal is a polished product interface with editable source and a shorter path from setup to working screens. It offers an opinionated but adaptable component layer, larger blocks, a registry workflow and a choice among supported primitive bases. Most product teams benefit more from that assembled surface than from creating every styled abstraction above raw primitives. Teams can still choose the Radix base and drop to raw Radix for specialized components, but they can also remain on Base UI or select React Aria; the open-code workflow, not a mandatory Radix dependency, is the stable reason to choose shadcn/ui.
Verdict
For the buyer this page targets—a product team that needs an accessible, attractive React interface quickly and wants the resulting source under its own control—shadcn/ui is the winner. It removes a large amount of repetitive assembly, exposes the code for direct adaptation and now lets the team choose the primitive base that fits its constraints. That verdict does not claim shadcn/ui is technically superior to Radix or that Radix powers every shadcn/ui installation. It says the higher-level open-code system is the more productive default when shipping the application matters more than designing a component platform from first principles.
Radix Primitives is the better winner for the narrower but important design-system case: teams that want a low-level, unstyled and centrally versioned behavioral foundation and are prepared to design everything above it. The decision is therefore about starting layer and ownership boundary. Choose Radix when primitives are the intended product infrastructure; choose shadcn/ui when finished, editable components are the intended starting point. If shadcn/ui plus Radix is the desired combination, initialize the Radix base deliberately and use raw Radix only where the copied component layer no longer provides enough structural control.