Blog
4 min read

What Is shadcn/ui? The Component Collection Behind Lovable and v0 Apps

shadcn/ui isn't a normal component library — it copies component code into your project so you own it. What shadcn/ui is, how the CLI works, what's in a components/ui folder, why AI builders use it, and how to customise and update it.

If your app came from v0, Lovable or Bolt, it probably has a folder called components/ui full of files like button.tsx, dialog.tsx and card.tsx. Those come from shadcn/ui — and it works differently from most libraries, which surprises people the first time they want to change something.

The short version

shadcn/ui is a collection of well-built React components — buttons, dialogs, menus, forms, tables — that you copy into your project as source code. You don't install it as a package and import from it. The code lives in your repository, and you own it.

Its tagline describes itself as "not a component library" but a way to build your own.

Normal library vs shadcn/ui

With a normal component library, you install a package:

npm install some-ui-library

The component code lives inside node_modules. You can pass options to it, but changing how it works means fighting the library or waiting for its authors.

With shadcn/ui, you run its CLI:

npx shadcn@latest add button

The CLI writes components/ui/button.tsx into your project. That file is now yours: plain React and Tailwind code you can read and edit.

What it's built on

  • React for the components. (What is React?)
  • Tailwind CSS for styling — the long class lists you see inside each file.
  • Headless UI primitives (such as Radix UI) for the hard parts: keyboard navigation, focus handling, screen-reader support. That's why shadcn dialogs and menus are accessible out of the box.

Why AI builders use it

  • Good defaults. The components look clean without customisation, which makes generated apps look professional.
  • Source code in the project. An AI tool can read and modify a component directly, rather than guessing at a library's options.
  • Accessibility handled. Keyboard and screen-reader behaviour comes from the primitives underneath.
  • Popularity. So much shadcn/ui code exists that models write it fluently.

What's in your project

A typical shadcn/ui project has:

  • components/ui/ — the copied components.
  • components.json — the CLI's settings (where to put files, style choices).
  • A lib/utils.ts with a cn() helper that merges Tailwind class names.
  • Theme colours defined as CSS variables (like --primary) in your global CSS, which is how light and dark mode work.

Customising it

Because you own the code, you have two easy ways to change things:

  1. Change the theme — edit the CSS variables to change colours and corner radius everywhere.
  2. Edit the component — open button.tsx and change it. Add a variant, change the padding, anything.

Tip for AI-built apps: ask your AI tool to change the theme variables for site-wide changes, rather than editing dozens of individual components. It keeps things consistent.

The trade-off: updates

Since the code was copied, it doesn't update itself. When shadcn/ui improves a component, your copy stays as it was. You can re-run add for a component to pull the new version, but it will overwrite your edits — so commit first and compare the diff. (How to read a diff.)

For most apps, this is fine: the components are stable and the ownership is worth it.

Common problems

  • "Module not found: @/components/ui/..." — the @/ path alias isn't configured, or the component was never added. Run the add command for it. (File paths explained)
  • Styles missing — usually a Tailwind version or configuration mismatch.
  • Hydration warnings with themes — common when the light/dark theme is decided in the browser. See Next.js hydration errors.

The summary

  • shadcn/ui copies component source into your project instead of installing a package.
  • Components are React + Tailwind on top of accessible primitives.
  • AI builders use it for good defaults and editable code.
  • Customise via theme variables; updating means re-adding and reviewing the diff.

EasySpawn gives Claude Code a server where it can run your app and see your components rendered, so UI changes get checked in the real thing, not just in the code. See how it works or join the waitlist.

Related: What Is Tailwind CSS? · How to Deploy a v0 App · How to Deploy a Lovable App to Production · What Is a Framework?

Keep reading