shadcn/ui alternatives for React components that survive edge cases
Note: I wrote this with AI help and then edited it myself. The test cases are real ones from the Brio UI repo.
I like shadcn/ui. It gives you buttons, dialogs, tabs and selects as source files you own, and that model changed how a lot of us build React apps. I build Brio UI on the same idea: you copy one file into your project and it’s yours.
The gap shows up one level higher. A pricing section, an FAQ with search, a one-time code input. These are the parts you build on top of the primitives, and they are where my bugs used to live. Prices in yen overflow the card. A German compound word pushes the FAQ off a phone screen. Someone pastes a six-digit code into the second box.
This post is about what to use next to shadcn/ui when those composed parts keep breaking.
What shadcn/ui gives you, and what it leaves to you
shadcn/ui is a set of primitives with good defaults. You run the CLI, the file lands in components/ui, and you style it from there. That's the right call for a button. It's a lot of work for a pricing table, because the pricing table is where the real-world data comes in: currencies, long plan names, locales that group digits differently, people who drag the toggle halfway and let go.
Nobody ships a primitive that handles your pricing copy. You end up writing that layer yourself, every project.
The test I use: the worst case, not the demo
Before I call a component done, I give it two fixtures. One is the nice demo data. The other is the worst thing I can think of. This is a method I took from Emil Kowalski: design for the ugly input first, and the pretty one takes care of itself.
Get Harjot Singh Rana’s stories in your inbox
Join Medium for free to get updates from this writer.
For the Pricing Toggle, the worst case includes:
- a plan called “Enterprise Unlimited Plus (annual commitment, invoiced, minimum 250 seats)”
- a price of 9,999,999 per month
- a negative price (a credit)
- a plan where yearly costs more than monthly
- sub-cent API pricing in Kuwaiti dinar with 3 decimals
- yen, Arabic-Indic digits, Devanagari digits and Indian lakh grouping
Then I screenshot it at 320 pixels wide and keep that screenshot as a visual baseline, so a later change can’t quietly break it.
The FAQ gets the same treatment: 120 questions with 4 open on load, a 200-character question with a 79-character German compound, an unbroken 130-character URL, questions in Japanese, Arabic, Chinese and Hindi, a right-to-left instance, and a javascript: link that has to stay hidden.
Where else to look
If you need more than shadcn/ui, these are the places I’d check, depending on the job:
- Radix UI or Base UI if you want unstyled, accessible primitives and plan to do all the styling yourself.
- Origin UI (now at coss.com/origin) if you want a big collection of copy-and-paste app UI components built with Tailwind CSS and React.
- Magic UI or Aceternity UI if you want components and templates for a landing page.
- Brio UI if you want the everyday composed parts (pricing toggle, FAQ, code input, contact form) with the edge cases already tested.
They mix fine. Brio components only depend on React and Motion, so they sit next to shadcn/ui in the same project without fighting it.
What a Brio component looks like
Each component is a single file. Here’s the Pricing Toggle: drag the switch halfway and every price sits halfway between monthly and yearly, then it snaps when you let go.
Install it with the Brio CLI:
npx brio-ui add pricing-toggleor with the shadcn CLI, if that’s what your project already uses:
npx shadcn@latest add https://brioui.com/r/pricing-toggle.jsonUsage is small:
import { Billing, BillingPrice, BillingSwitch } from '@/components/brio/pricing-toggle'
export function ProPlan() {
return (
<Billing>
<BillingSwitch />
<BillingPrice monthly={12} yearly={9.6} suffix="/mo" />
</Billing>
)
}Every component supports light and dark themes and respects reduced motion. The free ones are MIT licensed.
Which one should you pick
Keep shadcn/ui for primitives. When you notice you’re writing the same pricing, FAQ or code input logic for the third time, and fixing the same overflow bug for the third time, that layer is worth replacing with something that has already been tested against bad data.
The free Brio components are at brioui.com. Try the worst-case data from your own app on them and tell me what breaks.









