Overview
shadcn/ui is a CLI and a registry that writes accessible, Tailwind-styled component source into your repo; you own and edit that code. Current scaffolds target Tailwind v4 and React 19 and build on Radix (radix-ui), Base UI (@base-ui/react), or React Aria, chosen at init.
Run init once per project
npx shadcn@latest init # existing project
npx shadcn@latest init -t next # new project: next, vite, start, react-router, laravel, astroinit writes components.json, the cn helper, and the CSS variables, and create is an alias. For a new project, shadcn/create builds a preset visually and prints the matching init --preset ... --template ... command. Use --base radix|base|aria to choose the primitive library (base is Base UI) and --no-css-variables only if you accept utility-class colors.
Treat these components.json fields as permanent
style, tailwind.baseColor, and tailwind.cssVariables cannot change after init; switching cssVariables means deleting and reinstalling components. Leave tailwind.config blank on Tailwind v4. The default style is deprecated. Check that aliases match your tsconfig paths before the first add; they set every import path the CLI writes.
{
"tailwind": { "config": "", "css": "app/globals.css", "baseColor": "neutral", "cssVariables": true },
"aliases": { "components": "@/components", "ui": "@/components/ui", "utils": "@/lib/utils" }
}Add components one at a time
npx shadcn@latest add button dialog
npx shadcn@latest add dialog --dry-run # preview changes
npx shadcn@latest add dialog --diff # compare with your edited copyAdd only what the next feature uses; each file is code you must review and maintain. After init and the first add, confirm that globals.css has the :root and .dark blocks (a failed write leaves every component with broken tokens) and that the primitive package, class-variance-authority, clsx, and tailwind-merge landed in package.json; an interrupted install makes lib/utils.ts fail with a missing module.
Own the source and pull upstream changes by diff
Commit components/ui/* as first-party code and review it in PRs. There is no npm update for component markup; to take an upstream fix, run add <name> --diff or --dry-run, then port the lines you want or accept --overwrite. The scaffold also adds the shadcn package because your CSS imports shadcn/tailwind.css; npx shadcn@latest eject inlines that file and removes the dependency.
Keep primitive accessibility intact
Dialog, Popover, Select, Tabs, and Menu inherit focus management, keyboard handling, and ARIA wiring from the chosen primitive library. Do not replace a Dialog with a div and a portal, and do not strip forwarded aria-* props. Test Tab, Shift+Tab, Enter, Space, Esc, and arrow keys on each flow. If the design needs a different structure, edit the component file instead of rebuilding the behavior elsewhere.
Know what changed for Tailwind v4 and React 19
- Components use plain function components with a
data-slotattribute for styling hooks;forwardRefis gone. tw-animate-cssreplacedtailwindcss-animate, andtoastis deprecated in favor ofsonner.- Tailwind v3 and React 18 projects keep working; new components stay on v3 until you upgrade.
Next steps: theming in shadcn-theming, composition in shadcn-composition, and forms in shadcn-forms.