Skip to content
OTFotf
All posts

Shadcn/ui alternatives: when to switch and what to pick instead

D
DaveAuthor
8 min read
Shadcn/ui alternatives: when to switch and what to pick instead

Shadcn/ui's actual innovation is small and easy to miss: a CLI drops a styled component into your codebase instead of installing a package. You own the source. You fork it when your design changes. For a web-only React app on utility CSS, that pattern is still the cleanest default we have. The project describes itself plainly: "This is not a component library. It is how you build your component library" — built on open code you can modify and a composable interface (shadcn/ui docs).

The question isn't "is shadcn good." It's "is shadcn right for this project." Three cases break it: the same component has to render on iOS and Android without a webview, theming has to reach past utility-CSS variables, or npm update has to actually move your components. Each case has a different answer.

1. The decision tree in 30 seconds

Answer these in order:

  1. Native required (iOS or Android)? Yes → cross-platform SDK or native toolchain. No → continue.
  2. npm update required? Yes → maintained npm library (Mantine, MUI, Chakra). No → continue.
  3. Utility CSS + React + web-only? Yes → shadcn. Done.

Everything else is a specific-answer problem: per-tenant themes, brand-strict design systems, large-org governance, accessibility audits — each has a different right answer, and you should pick based on the constraint that's actually breaking you.

The rest of this post expands each branch with the trade-offs.

2. Web-only React: why shadcn is still the right call

If you're building a SaaS dashboard, a marketing site, an internal tool — anything that ships to a browser — use shadcn. The pattern (CLI drops a styled component into your repo, you own the source, you can rewrite any part of it) is genuinely the best default we have for React + utility CSS. The alternatives below solve specific problems shadcn doesn't, not a "better shadcn."

What it gives you:

  • Accessibility primitives underneath (focus traps, ARIA, keyboard nav — done)
  • CSS variables for theming, swappable per brand
  • A cn() helper and a variant API that codegen tools and Cursor understand
  • Dozens of components covering the dashboard essentials (Button, Dialog, Sheet, Form, Table, Toast, Tooltip, …)

What it costs you: every component is hand-vendored. When shadcn pushes a fix, you get it by re-running the CLI or merging a PR. There's no npm update @shadcn/ui. And the styling layer is utility classes — not because that's bad, but because every styling assumption that isn't utility classes (CSS-in-JS, CSS modules, Panda, vanilla CSS) means rewriting.

So: shadcn = right when you're web-only, utility-CSS-comfortable, and want a one-time copy-into-the-repo model.

One codebase. iOS, Android, and web.

The Fitness Kit ships with auth, a database, and a backend already connected — no setup. Live demo at fitness-preview.otf-kit.dev.

See the live demo

3. Native required: where shadcn stops at the browser

The hard limitation: shadcn is React + DOM. A <Dialog> for iOS isn't a <div role="dialog"> — it's a modal presentation with a swipe-down-to-dismiss gesture and safe-area insets the web component knows nothing about. The web component won't render in a native shell without a webview, and a webview is exactly what most teams say they don't want.

The real options here:

OptionHow it gets to nativeTrade-off
shadcn + React Native WebSame React code, RN renders native primitivesRNW hits visual parity limits; accessibility tree differs from DOM; two style systems
Cross-platform JS primitives (NativeBase, etc.)Native UI from JSDifferent API surface from shadcn; rewriting
Flutter / SwiftUI / ComposeTruly native, separate codebasesDifferent language and toolchain per platform
OTF (@otfdashkit/ui + @otfdashkit/ui-native)Same component name + props, web and native share an APISmaller ecosystem than shadcn; paid kits on top of the free SDK

If "one component, web + iOS + Android, one API" is the actual requirement — not a wish — that's a small list. OTF's free MIT SDK is on it.

a token source — design-tokens.json — fanning out to web CSS variables, iOS colors, and Android theme values

4. Themes that need to reach past the browser

Shadcn themes are CSS variables plus utility-class mappings. That covers 95% of brand work. Where it starts to break:

  • Per-tenant theming at runtime (white-label SaaS where each customer gets their own palette from a DB column)
  • Themes that aren't "light/dark" — a "high contrast accessibility" mode, a deuteranopia mode, a "brand event" mode
  • Tokens that need to drive native (iOS/Android) at the same time as web — utility-CSS doesn't compile to a native color value

For per-tenant at runtime on web only: shadcn works fine, you just need a server-driven CSS variable override. For cross-platform theming where the iOS button color must match the web button color from the same JSON: shadcn doesn't have an answer, and you need a token system that reaches all three platforms from one source.

5. When you want npm update to actually update your components

This is the underrated one. Vendored code is great until:

  • A security CVE lands in an accessibility primitive and you have to find every <Dialog> you copied six months ago
  • shadcn ships a fix and you don't see it because no node_modules diff alerts you
  • Your team grows from 3 to 30 and now you have 30 inconsistent copies of Button.tsx

If you want the package to actually move under you — like every other node_modules dependency — you don't want shadcn. You want a library you install.

Trade-offs of an npm-installed library:

  • You give up the "fork anything" freedom. Bug fixes are upstream PRs.
  • Bundle size is shared; code-splitting is the library's job.
  • You get security patches, version upgrades, and one source of truth.

The honest list of maintained React component libraries with this model: Mantine, Chakra, MUI, Ant Design, Park UI, Radix Themes, Ark UI. Mantine's documented scope is more than 120 customizable components plus 70 hooks (Mantine), and MUI's is React components implementing Material Design (MUI Material UI) — both install, version, and update like every other npm dependency.

6. The alternatives, compared

NeedPickWhy
Web-only React + utility CSS, one-time setupshadcn/uiBest defaults, owned source
Web-only, npm-updateable, batteries includedMantine120+ components, MIT, hooks included
Web-only, strict design system, large orgMUI / ChakraOpinionated, accessible, mature
React + native (iOS/Android), one APIOTF SDKFree MIT, same <Button> everywhere
Brand-strict cross-platform from one token sourceOTF SDK + tokensOne JSON → web + iOS + Android
Just native (iOS or Android only)SwiftUI / Compose / FlutterNative toolchain is the right answer

shadcn copy-paste vs npm-installed library vs cross-platform SDK

7. What OTF actually gives you if you go that way

State the outcome, not the parts.

The free MIT SDK ships three packages: @otfdashkit/ui for web, @otfdashkit/ui-native for iOS and Android, and @otfdashkit/tokens for the shared design tokens. ~200 components. The same <Button>, the same <Dialog>, the same <Card> — same name, same props, same look — render on web, iOS, and Android from one codebase. Distribution is your choice: copy-paste CLI or npm install.

npm install @otfdashkit/ui @otfdashkit/ui-native @otfdashkit/tokens

Three things that aren't obvious from the landing page:

  1. One token source, three platforms. Design tokens flip one theme across web and mobile. The iOS button and the web button are the same color because they read the same color.primary.500 token from one JSON. Per-tenant theming becomes a token swap, not a rebuild.

  2. The kits ship with agent configs. Every full-stack kit (SaaS Dashboard, Fitness, Booking — $99 each, Everything Bundle $149) comes with CLAUDE.md, .cursorrules, and 20+ tested prompts under ai/prompts/. A coding agent extends the kit instead of regenerating it. Plus 15 single-page landing templates at $9 each when you just need a marketing page.

  3. One script ships to production. A single deploy script wires custom domain, DNS, TLS, and the mobile build pipeline. A 24-item design checklist runs before any kit ships, so the code you copy meets a documented bar — not "works on my machine."

Demos: saas.otf-kit.dev (web) and fitness-preview.otf-kit.dev (mobile). Or browse everything at OTF templates.


Pick the library that matches the constraint you can't negotiate. For most web-only React projects, that's shadcn. For native-required work, that's a smaller list — OTF's free SDK is on it. The honest answer is that "the best component library" is the wrong question. The right question is which constraint you can't bend, and which library is built around that constraint.

Keep reading

Sources

  • shadcn/ui docs — "This is not a component library. It is how you build your component library"; open code and composition principles.
  • Mantine — more than 120 customizable components and 70 hooks.
  • MUI Material UI — React components implementing Material Design.
  • OTF templates — the SDK and kit lineup referenced in this post.
design-systemreact-nativecross-platform
OTF Fitness Kit

Stop wiring. Start shipping.

  • Login, database, and backend already connected — nothing to set up
  • iOS + Android + web from one codebase
  • AI configs pre-tuned + 40+ tested prompts included