shadcn/ui in 2026: the copy-paste model that won — and how to use it as a real design system
You don't install shadcn/ui — you own the code. Two years in, the model has won. Here's how to use it as a proper design system foundation, not just a starter kit.
shadcn/ui is not a component library in the traditional sense — you don't add it to node_modules, it doesn't have a version to upgrade, and there's no changelog to track. You run a CLI that copies the component source directly into your project, and from that point on, the code is yours to read, modify, and own. Two years since the model took off, it's the starting point for the majority of new React projects. Here's how to make it a foundation rather than a shortcut.
Why the ownership model matters
Traditional component libraries create a dependency ceiling: the library's API is the API. When you need a Dialog that behaves slightly differently, you work around the library's constraints. With shadcn/ui, the Dialog is in your components/ui/ folder. You read it (it's ~80 lines of clean Radix UI + Tailwind), understand it, and modify it. The components are built on Radix UI primitives which handle accessibility — focus trapping, keyboard navigation, ARIA — so you get those behaviors for free while retaining full markup and style control.
# Add components directly to your codebase
npx shadcn@latest add button dialog select
# The component lives in your repo — fully editable
# components/ui/button.tsx <- you own this
# components/ui/dialog.tsx <- you own this
# Check for upstream updates as a diff, not a lockfile bump
npx shadcn@latest diffTheming for multi-brand setups
shadcn/ui's theming model maps cleanly to multi-brand design systems. Each brand defines its own CSS variable values in a :root block — --primary, --radius, --font-sans — while the component files remain identical across brands. On Appesto, every product shares the same component library and component source, with brand-specific themes applied at the :root level. A theme switch is a single CSS class change on the html element.
The parts that need extra work
- Date pickers and rich text editors are not in the default set — you'll need react-day-picker or Tiptap and custom theming to match.
- Data tables with sorting and pagination require TanStack Table integration — the base Table component is layout-only.
- Motion and entrance/exit animations are minimal — add Framer Motion or CSS transitions to components that need them.
- The CLI update model (npx shadcn diff) gets complex when you've heavily customised a base component — comment your customisations so you know what to preserve on updates.
Written by Appesto Engineering.