Source-owned components vs npm UI libraries
· 6 min read · react · tailwind · shadcn · architecture
Why copy-paste, source-owned React components beat black-box npm UI libraries for ownership, bundle size, and AI-assisted development — and how Lerpa UI's shadcn-compatible registry works.
Most React UI libraries ship as an npm package: you npm install a name, import components, and accept whatever markup, styles, and behaviour the maintainer decided on. It is fast to start, but you do not own the result. A source-owned model — the one shadcn popularised and Lerpa UI follows — inverts that. The component source is written into your repository as a plain file. This post explains the trade-offs and why source-owned wins for most teams.
The black-box problem
With a packaged library, customisation runs through whatever props and theme hooks the author exposed. Need a markup change they did not anticipate? You are wrapping, overriding, or forking. Upgrades can silently change behaviour, and you ship the library's entire surface area — including the parts you never use.
Source-owned components are different. When you run lerpa-cli add <id>, the component lands in src/ui/ as a readable .tsx file. Read it, edit it, delete half of it — it is yours. There is no version to lock and no upstream that can break your build.
Bundle size and tree-shaking
Because you only add the components you use, there is no dead code to tree-shake out of a monolithic package. Each component is a single file with explicit imports, so your bundler sees exactly what ships. Lerpa UI components keep styles in Tailwind classes and tokens in CSS variables, so there is no runtime style engine tax either.
How the shadcn-compatible registry works
A registry is just JSON that describes a component: its files, dependencies, and the imports to rewrite on install. Lerpa UI's registry is shadcn-compatible, so the same component installs two ways:
# Lerpa CLI
pnpm dlx lerpa-cli add button
# or the shadcn CLI, pointed at the registry URL
npx shadcn add https://lerpaui.com/r/button.jsonOn install the registry rewrites internal import paths (for example ../lib/cn becomes @/lib/cn) so the file drops cleanly into a standard project. You can read more in the CLI reference.
Why this matters for AI-assisted development
Source-owned components are also the right shape for AI agents. Because the catalog is described in a machine-readable llms.txt and exposed through an MCP server, an assistant like Claude or Cursor can search the catalog, pick the right component, run the CLI, and wire it up — then keep editing the file it just wrote, because the file is right there in your repo.
When a packaged library is still fine
If you want a single dependency to upgrade centrally and you are happy with the library's defaults, a packaged library is less code to manage. Source-owned shines when you expect to customise, care about bundle size, or want AI agents working directly on your component source.
Try it
Browse the component gallery, read the installation guide, or skim the FAQ for how updates work. Everything is MIT licensed and free.