Skip to content
OTFotf
All posts

Shadcn/ui Alternatives: When to Use Them and Why

D
DaveAuthor
7 min read
Shadcn/ui Alternatives: When to Use Them and Why

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 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
  • ~40 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 UIViewController modal with a swipe-down-to-dismiss gesture, a safe-area inset, and a UIPresentationController for the chrome. 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 UIColor extens

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 UIColor or a Compose Color

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.

6. The alternatives, compared

NeedPickWhy
Web-only React + utility CSS, one-time setupshadcn/uiBest defaults, owned source
Web-only, npm-updateable, batteries includedMantine~120 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).


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.

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