A React component foundation shapes how your team styles, distributes, and maintains UI code throughout a project's life cycle. shadcn/ui and Radix UI sit near the top of those decisions, and both have become the starting point for a big slice of modern React apps. They aren't rivals, though. shadcn/ui is built on top of Radix Primitives by default, so picking one usually means working with the other underneath.
This guide covers what each project is, how the two relate in practice, where they differ, and when to reach for one, the other, or both.
Link to headingWhat is shadcn/ui?
shadcn/ui is a React component distribution model built by shadcn at Vercel. Instead of installing components as a package from npm, you pull the source files directly into your repo using the shadcn CLI. The components land in your codebase, and from that point on, your team reads, edits, and versions them like any other component you'd author yourself.
Link to headingThe copy-paste distribution model
Traditional React component libraries live inside node_modules, so the source you use sits one npm install away. shadcn/ui flips that pattern. Running npx shadcn@latest add button pulls the component's source from the registry, writes it into your configured UI components directory (commonly components/ui/), and installs any dependencies it needs.
Your app owns the component from the moment it lands. Markup, classes, variants, and behavior all sit inside files your team reviews in pull requests, which makes changes a normal part of the repo rather than a fork of a third-party package.
Link to headingThe Radix Primitives and Tailwind CSS foundation
Interactive shadcn/ui components delegate accessibility behavior, keyboard navigation, and focus management to Radix Primitives. That's why the comparison with Radix confuses people on first read: the two projects share the same behavioral layer in most of shadcn/ui's interactive components.
The shadcn/ui layer handles everything above that, with Tailwind CSS utility classes, CSS custom properties for theming tokens, and class-variance-authority for managing variants. Tailwind is a required dependency, which is an architectural commitment rather than a default setting.
Link to headingThe blocks, charts, and v0 connection
Beyond individual components, shadcn/ui ships pre-composed UI patterns called Blocks that combine primitives into dashboards, authentication flows, and sidebar layouts. Charts are built with Recharts, while command palettes, carousels, drawers, and toasts pull in focused libraries such as cmdk, Embla, Vaul, and Sonner.
The wider surface connects to v0, Vercel's AI product for building apps, websites, and agents. v0 generates React code using Tailwind CSS and shadcn/ui as part of its default stack, and the shadcn Registry Starter includes "Open in v0" buttons for each component so that the generated code matches the conventions already in the repo.
Link to headingWhat is Radix UI?
Radix UI is an open-source React component project maintained by WorkOS. It ships as a standard npm library that handles the parts of building UI that are easy to get wrong: keyboard interactions, ARIA attributes, focus management, and the accessibility details that make components work with screen readers.
The project splits into four sub-projects, each covering a different layer of the UI stack: Primitives, Themes, Colors, and Icons.
Link to headingPrimitives for behavior and accessibility
Radix Primitives is a low-level, unstyled component library focused on accessibility, customization, and developer experience. Components encapsulate the parts of the WAI-ARIA design patterns most teams don't want to reimplement, including aria attributes, roles, keyboard interactions, and focus management.
The library ships with zero styles, which lets any CSS approach layer on top without fighting the default design. State exposes itself through data-state attributes, so selectors like [data-state="open"] work across CSS Modules, styled-components, or Tailwind, and the asChild prop gives teams full control over the rendered element.
Link to headingThemes for pre-styled components
Where Primitives handles behavior, Radix Themes is a separate styled component library built on top of Primitives. It ships its own CSS, a <Theme> provider, and a pre-built visual language so teams can drop it in without designing the look themselves.
Themes exists for projects that want a packaged system, and its styling is part of the install rather than an unopinionated layer. Pairing Radix Themes with Tailwind CSS needs careful thought about CSS layer ordering, because the styling tradeoffs apply to Themes rather than to Primitives.
Link to headingColors and Icons for design tokens
Radix Colors is an accessible color system with dark mode support, alpha variants, and contrast-oriented scales. Each scale step maps to common interface uses such as backgrounds, borders, overlays, and text, giving a design system a structured starting point rather than a raw palette.
Radix Icons is a set of 15×15 SVG icons exported as React components. Together, Colors and Icons round out the design-token and asset layer of the broader Radix stack without forcing adoption of the other sub-projects.
Link to headingKey differences between shadcn/ui and Radix UI
The comparison sits between two layers of the stack, not two rival libraries. Radix Primitives provides the behavior layer used by many production React apps, while shadcn/ui is a styling, distribution, and design-system layer that uses those primitives in most of its interactive components.
Link to headingDistribution model
Radix UI follows the standard React distribution pattern. Projects install a package like @radix-ui/react-dialog (or the umbrella radix-ui package) and get component updates through the package manager like any other dependency. shadcn/ui copies source files into the repo with its CLI instead, so the updates that arrive through npm update never touch those components.
That difference has meaningful maintenance consequences. Upstream bug fixes and new features in shadcn/ui don't automatically propagate to your copied files, which trades automatic maintenance for ownership. Projects using Radix directly stay tied to npm update for everything, including the behavior layer.
Link to headingStyling approach
Zero styling is the core design choice behind Radix Primitives, making it compatible with any styling approach, from CSS Modules to styled-components to Tailwind CSS. shadcn/ui commits to Tailwind CSS, CSS custom properties, and class-variance-authority, which creates a consistent system at the cost of tying component code to Tailwind itself.
The tradeoff is architectural rather than theoretical. A project already running CSS Modules, Emotion, or vanilla-extract can drop in Radix Primitives without changing its styling model, while shadcn/ui earns its keep when Tailwind is already part of the stack.
Link to headingCustomization and code ownership
Ownership is the primary split between the two projects. With Radix, your team owns the visual layer but not the behavior, because accessibility and focus logic sit inside node_modules.
shadcn/ui lands every file inside the repo from the moment its CLI copies them, which puts markup, classes, variants, and component APIs under direct team control. Accessibility adjustments are implemented as local patches rather than upstream PRs, and design-system tweaks are made in the same files that ship to production.
Link to headingAccessibility
Both projects share the same accessibility foundation for Radix-backed components, because shadcn/ui delegates ARIA attributes, keyboard interactions, and focus management to the underlying primitive. Radix follows the Radix accessibility docs, which align with WAI-ARIA authoring practices and are tested across modern browsers and assistive technologies.
The practical difference is where fixes live. A shadcn/ui project can patch accessibility behavior in the copied source file, while a Radix-only project depends on upstream package updates unless the team forks a primitive.
Link to headingDeveloper experience and learning curve
Radix Primitives has a steeper initial learning curve because your team designs the visual layer from scratch, and the tradeoff is complete freedom over how components look. shadcn/ui starts a project with prewritten styles, a CLI that scaffolds components in seconds, and a consistent code structure that reads the same across the catalog.
The split shows up early in a project. Radix asks teams to invest design time up front, while shadcn/ui pushes that work later, after the copied files are already available in the repository for editing.
If you're comparing more than two React component systems, see Material UI as a related packaged library baseline.
Link to headingWhen to choose shadcn/ui
shadcn/ui is the better starting point when Tailwind is already in the stack, and your team wants to own its component code:
Tailwind-first projects: Tailwind CSS is already installed, or the project has planned to use it as the styling approach. shadcn/ui extends the same utility-class pattern into the component layer, so the mental model stays consistent from page to component.
Customized design systems: A design team needs to reshape markup, variants, or behavior beyond the defaults. Because every component is a source file in the repo, the editing surface matches the design system's ambition.
AI-assisted development: Engineering teams using coding agents (like Claude Code) benefit from having component source directly in the repository, since the files are available for direct review, generation, and editing alongside the rest of the app.
Fast iteration from a working starting point: A team needs to ship interfaces quickly without a long design phase. The default styles, Blocks, and charts cover most standard application patterns out of the box.
The AI-assisted case also connects to v0 workflows, where generated code matches the shadcn/ui conventions already in the repo.
Link to headingWhere Radix UI fits best
Radix Primitives is the stronger fit when the styling stack isn't Tailwind or when the project needs raw building blocks without a visual opinion. The scenarios below line up cleanly with that model:
Non-Tailwind stacks: Projects using CSS Modules, Emotion, styled-components, or vanilla-extract keep their styling model intact, because Radix Primitives ship with zero styles.
Bespoke design systems: Design teams that deliver fully specified tokens, spacing, and motion benefit from starting at the primitive level rather than adapting defaults.
Flexible markup requirements: Components that need arbitrary HTML between compound parts have more structural flexibility with Radix, whereas shadcn/ui's copy-paste conventions can become a constraint.
Shared React library contexts: Engineering groups publishing components as part of a library they distribute benefit from Radix's package-based updates rather than a CLI copy-paste.
Radix Themes is a separate call: it suits projects that want Radix's accessibility foundation and a pre-styled component set, rather than unstyled primitives.
Link to headingUsing shadcn/ui and Radix UI together
Many production projects end up using both, since shadcn/ui is already built on Radix Primitives by default. The harder call is what to do when a custom component needs behavior sitting outside the shadcn/ui catalog, and projects running both side by side tend to converge on these patterns:
Radix Primitives for custom behaviors: Components the shadcn/ui catalog doesn't cover use raw Radix packages directly, with Tailwind classes layered on top to match the rest of the UI.
Shared token system: The
cn()utility from shadcn/ui consistently merges class names, so custom Radix-based components share the same Tailwind tokens and theming variables as the rest of the app.Local accessibility patches: A copied shadcn/ui file can be patched directly when a specific flow needs different focus or keyboard behavior, while the underlying Radix package stays on its standard release cadence.
What works less cleanly is mixing two complete styled-component systems in a single app. Combining Radix Themes with the shadcn/ui Tailwind layer doubles up on design tokens, CSS cascade order, and theming APIs, which usually creates more work than either approach saves on its own.
Link to headingDeploy shadcn/ui and Radix UI apps on Vercel
Both deploy like any other React or Next.js project on Vercel, with no platform-specific configuration for the component layer itself. shadcn/ui files live in components/ui/, Radix packages live in node_modules, and the build pipeline treats them the same way it treats the rest of the React source.
Preview deployments apply directly to component-heavy UI work. Every pull request ships a unique URL for the new component variant, theme change, or accessibility fix, so design review occurs in a production-identical environment before the change reaches the main branch.
The SaaS Starter template is a Next.js project already wired with shadcn/ui, providing a working starting point for your team.
Link to headingMaking the right call between shadcn/ui and Radix UI
The framing of "shadcn/ui vs Radix UI" suggests a head-to-head choice that doesn't exist. shadcn/ui is a styling, distribution, and design-system layer built on Radix Primitives, so picking shadcn/ui often means picking Radix UI for the behavior underneath.
The decision is between using Radix Primitives directly with your own styling approach or adopting shadcn/ui's Tailwind-based conventions and copy-paste distribution. Projects already committed to Tailwind and shipping standard application UIs will move faster with shadcn/ui, while projects on non-Tailwind stacks, bespoke design systems, or components that need more structural flexibility should reach for Radix Primitives directly.
Either choice deploys the same way on Vercel. If you want to evaluate the workflow in practice, start a new project or browse templates to skip the blank-page problem.
Link to headingFrequently asked questions about shadcn/ui and Radix UI
Link to headingIs shadcn/ui a replacement for Radix UI?
No. shadcn/ui is built on top of Radix UI for most of its interactive components, not a replacement for it. The Radix variants of Dialog, Popover, Select, and similar components import directly from @radix-ui/react-* packages, so a shadcn/ui app running on Vercel keeps Radix in the dependency graph at build time.
Link to headingCan I use shadcn/ui without Tailwind CSS?
Not as designed. Tailwind CSS is a required dependency, and the copied component files rely on utility classes and CSS custom properties throughout. Projects that want to skip Tailwind on a Vercel deployment are usually better off reaching for Radix Primitives directly, which ship unstyled and pair with any CSS approach.
Link to headingWhich has better accessibility?
They share the same accessibility implementation for Radix-backed components, because shadcn/ui delegates ARIA attributes, keyboard interactions, and focus management to Radix. The practical difference is where patches happen: a shadcn/ui codebase fixes issues in the copied source, while a Radix-only project waits on upstream updates unless it forks. Both patterns ship cleanly through a Vercel deployment pipeline.
Link to headingCan I run shadcn/ui and Radix UI together on Vercel?
Yes, and that combination is already the default for most shadcn/ui projects. The Vercel build pipeline treats the copied shadcn/ui files and the installed Radix packages the same way as any other React code, so preview deployments and production builds run without extra configuration.