Why I Open-Sourced My React Component Library (and What Happened Next)
200+ weekly NPM downloads in 3 months — what building vividoraUI taught me about DX and trust.
I didn't plan to build a component library. I planned to ship products faster.
Like a lot of frontend engineers, I started where everyone starts: I tried to make existing tools fit my workflow. Sometimes that meant pulling pieces from shadcn, sometimes it meant reaching for something heavier like MUI, and sometimes it meant copying the same button, modal, dropdown, and form patterns between projects and pretending that wasn't technical debt. After doing that for long enough, I realized I wasn't avoiding the work of building a design system — I was just doing it badly, one repo at a time.
That was the real beginning of vividoraUI.
The Gap I Kept Running Into
The market wasn't empty. That was never the problem. The problem was that the choices all came with tradeoffs I felt every week.
On one side, I liked the flexibility of shadcn-style composition. It gives you a great starting point, and I still think that model is one of the smartest things to happen in the React ecosystem. But for my use case, it still left too much assembly work at the application layer. I wanted components I could install and trust, not just patterns I needed to keep curating manually across projects.
On the other side, MUI solved a lot of problems, but it often felt like bringing in a full UI operating system when what I wanted was a clean, modern component layer. I didn't want to fight a styling abstraction, override defaults for hours, or explain to every new contributor why simple customization had suddenly become framework archaeology.
So I built the library I actually wanted to use: lightweight, composable, accessible, TypeScript-first, styled with Tailwind, and opinionated enough to be productive without becoming a cage.
The Technical Bets That Mattered
The first decision I got right was building on top of Radix UI primitives. I did not want to reinvent accessibility. The fastest way to create a fragile component library is to build interactive primitives from scratch and convince yourself you'll "polish accessibility later." Later usually never comes. With Radix, I could start from a foundation that already handled focus management, keyboard interactions, layering, dialogs, and popovers — all the invisible details users absolutely notice when they're broken.
The second big decision was going TypeScript-first from day one. Not TypeScript-compatible. Not "we'll add types later." TypeScript-first. That changed how I designed every component. Props had to be predictable. Variants had to autocomplete cleanly. If a component was flexible but the type signature made it confusing to consume, I treated that as a design bug.
The third decision was Tailwind CSS for styling. I wanted the library to feel native inside the modern React stack, especially for teams that already think in utility classes, tokens, and composable design primitives. Tailwind gave me a fast way to build consistent defaults without locking consumers into a complicated theming system too early.
The combination worked well: Radix for behavior, TypeScript for API safety, and Tailwind for styling velocity. What surprised me was how much discipline that stack still required — utility-first styling can get messy fast inside a reusable library, and variant systems become unreadable if you don't keep them tight.
Shipping to NPM Without Making Releases Painful
Publishing the first version to NPM was the easy part. Building a release pipeline I could trust was the real work. I knew early that if every release depended on me remembering a manual checklist, the library would decay. Open-source momentum is fragile. The second publishing becomes annoying, you start delaying releases. Then fixes pile up. Then contributors lose confidence. Then users stop updating.
So I automated the entire release path. The repository was structured like a real product, not a side project. Builds had to pass. Type checks had to pass. Package contents had to stay clean. Versioning had to be explicit. GitHub Actions handled the CI/CD layer so every push and release candidate went through the same pipeline: install, lint, test, build, validate package output, and publish on tagged release.
That did two things for me. First, it reduced stress — I wasn't wondering whether I had forgotten a build artifact or published the wrong files. Second, it made the project feel legitimate. A polished release pipeline signals that the library is meant to be used by other people, not just admired from a GitHub screenshot.
What Happened After Open-Sourcing It
The part I expected was feedback. The part I didn't expect was discovery.
Within three months, vividoraui crossed 200+ weekly downloads, and almost all of that came through organic discovery. No paid push. No launch campaign. Just consistent shipping, documentation, examples, and GitHub visibility — people finding it because it solved a real problem clearly enough to spread.
That was a weirdly emotional milestone. Not because 200 weekly downloads is internet-scale success — it isn't. But because it's enough to prove that strangers are trusting something you built. They're installing it into actual projects. They're betting a little bit of their time on your judgment. For an open-source maintainer, that feels bigger than the number itself.
It also changed how I thought about growth. Features get you attention, but clarity gets you retention. People didn't stick around because the button looked nice — they stuck around because the install process was simple, the docs answered real questions, and the library didn't make them work harder after installing it.
What I Learned About DX and Building in Public
The biggest lesson: DX is not decoration. It is the product. A component library is not just the code in src. It is the README, the prop naming, the examples, the error messages, the folder structure, the release notes, the migration path, the defaults, and the time it takes for someone to go from "this looks interesting" to "this is now in my app." Every point of friction gets multiplied across every user.
The second lesson: documentation is a feature, not a marketing layer. Clear examples beat clever abstractions. Showing real usage beats describing architecture. A well-documented component with 80% of the possible flexibility is usually more valuable than a hyper-abstract one nobody understands.
The third lesson was about building in public. It means shipping before everything feels finished, being honest when something is rough, and letting people watch you refine your taste in real time. That can be uncomfortable. It can also be incredibly clarifying — once people start using your work, vague opinions turn into concrete product decisions very quickly.
Open-sourcing vividoraUI made me a better engineer — not because it taught me how to build more components, but because it taught me how to think more seriously about the people on the other side of the install command.