Good components are expensive. You can spend weeks building accessible dialogs, dropdown menus, and form controls yourself, or install a traditional component library and inherit its design decisions.
By comparison, shadcn/ui offers a different approach. Its CLI copies the component source directly into your project, giving you accessible, styled components that you can edit from the moment they arrive. Pair that model with Tailwind CSS v4’s CSS-first configuration and Vite’s fast development server, and you get a setup that is quick to start and flexible enough to evolve with your product.
If this is your first time using the library, read our complete guide to using shadcn/ui for an overview of its component ownership model, registries, and customization workflow.
The only tricky part is the initial wiring. Tailwind CSS, the import alias, and the shadcn CLI need to be configured in the correct order. Miss one piece and init may stop before generating the files you need.
This guide walks through the complete setup for a React and TypeScript project, explains what every step does, and includes shortcuts and fixes for the most common errors.
Prerequisites
You need:
- Node.js
20.19+or22.12+, as required by current Vite releases - npm, pnpm, Yarn, or Bun
- A code editor and terminal
The command selector in each step supports npm, pnpm, Yarn, and Bun. Your selection is remembered across every command on the page.
The examples use Vite’s React and TypeScript template. JavaScript works too, but you will need a matching jsconfig.json alias before the shadcn CLI can resolve your project paths.
Setting Up shadcn/ui with Tailwind CSS v4 Using Vite
Follow these six steps in order to configure Vite, Tailwind CSS v4, and shadcn/ui correctly.
Step 1: Create the Vite project
Create a new React and TypeScript application:
pnpm dlx create-vite@latest my-app --template react-ts npx create-vite@latest my-app --template react-ts yarn dlx create-vite@latest my-app --template react-ts bunx --bun create-vite@latest my-app --template react-ts Move into the new project directory:
cd my-app
Install the project’s dependencies:
pnpm install npm install yarn install bun install The selector uses the create-vite executable directly, so the template option works consistently across all four package managers.
If you already have a React Vite project, open its root directory and continue with Step 2.
Your initial project should look similar to this:
my-app/
├── public/
├── src/
│ ├── App.tsx
│ ├── index.css
│ └── main.tsx
├── package.json
├── tsconfig.app.json
├── tsconfig.json
└── vite.config.ts
Step 2: Install Tailwind CSS v4
Install Tailwind CSS and its first-party Vite plugin:
pnpm add tailwindcss @tailwindcss/vite npm install tailwindcss @tailwindcss/vite yarn add tailwindcss @tailwindcss/vite bun add tailwindcss @tailwindcss/vite Open src/index.css, remove the starter styles, and replace them with:
@import "tailwindcss";
Replacing the file matches the official setup and prevents Vite’s starter styles from competing with your generated theme and application layout.
Tailwind CSS v4 does not require a tailwind.config.js file for this setup. Configuration and theme customization live primarily in CSS, and Tailwind automatically detects classes in your source files.
Do not start the shadcn CLI yet. The import alias must exist first.
Step 3: Configure the TypeScript path alias
shadcn/ui commonly generates imports such as:
import { Button } from "@/components/ui/button";
The @ alias needs to point to the src directory. Vite’s TypeScript template splits configuration across multiple files, so add the alias to both tsconfig.json and tsconfig.app.json.
Update tsconfig.json:
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
Next, add the same alias inside the existing compilerOptions object in tsconfig.app.json:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
Keep the other compiler options already generated by Vite. The shortened example only shows the properties you need to add.
The duplication is intentional. The root configuration helps tooling discover the project alias, while the app configuration ensures the editor and TypeScript compilation resolve imports used by the application.
Using JavaScript instead of TypeScript
If you created the project with --template react, add a jsconfig.json file at the project root:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
You still need the matching Vite alias from the next step because jsconfig.json helps your editor, not the runtime build.
Step 4: Configure Tailwind and the alias in Vite
Install the Node.js type definitions so TypeScript understands the path import and __dirname used in vite.config.ts:
pnpm add -D @types/node npm install -D @types/node yarn add -D @types/node bun add -d @types/node Replace the contents of vite.config.ts with:
import path from "path";
import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});
This configuration does two separate jobs:
tailwindcss()compiles Tailwind utilities through Vite.resolve.aliastells Vite how to resolve imports beginning with@during development and production builds.
The TypeScript path configuration from Step 3 is not enough on its own. TypeScript understands the alias for type checking and editor tooling, but Vite also needs a runtime resolution rule.
Step 5: Initialize shadcn/ui
Now run the CLI from the project root:
pnpm dlx shadcn@latest init npx shadcn@latest init yarn dlx shadcn@latest init bunx --bun shadcn@latest init The CLI performs preflight checks, detects Vite and Tailwind CSS, and prompts you for project options such as the component base, design preset, base color, CSS variables, icon library, and import aliases. You can accept the defaults or choose the options that match your design.
After initialization, the project will include files such as:
my-app/
├── components.json
└── src/
├── index.css
└── lib/
└── utils.ts
The exact generated CSS depends on the options and CLI version. In Tailwind CSS v4 projects, expect theme variables and Tailwind mappings in src/index.css rather than a JavaScript Tailwind configuration file.
The CLI also installs the dependencies required by the selected component setup and creates the cn utility in src/lib/utils.ts.
To understand every generated setting before changing it, see our complete components.json field guide.
Important: The base color and CSS variable strategy are initialization-time choices. You can edit the generated theme tokens later, but changing those fields in
components.jsondoes not regenerate existing CSS or components.
Step 6: Add your first component
Install the shadcn/ui button:
pnpm dlx shadcn@latest add button npx shadcn@latest add button yarn dlx shadcn@latest add button bunx --bun shadcn@latest add button The component is copied into:
src/components/ui/button.tsx
This is a real source file in your application, not a component imported from an opaque package. You can inspect it, customize it, and keep it under version control.
Replace src/App.tsx with the following example:
import { Button } from "@/components/ui/button";
function App() {
return (
<div className="flex min-h-svh items-center justify-center gap-2">
<Button>Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
</div>
);
}
export default App;
Start the development server:
pnpm dev npm run dev yarn dev bun run dev Open the local URL printed by Vite. Three visibly different, styled buttons confirm that:
- The
@alias resolves correctly. - Tailwind CSS compiles your utility classes.
- shadcn/ui’s generated theme is loaded.
- The component import works.
Adding Multiple shadcn/ui Components
You can add several components with one command:
pnpm dlx shadcn@latest add card dialog input label npx shadcn@latest add card dialog input label yarn dlx shadcn@latest add card dialog input label bunx --bun shadcn@latest add card dialog input label To install every component from the default registry, use:
pnpm dlx shadcn@latest add --all npx shadcn@latest add --all yarn dlx shadcn@latest add --all bunx --bun shadcn@latest add --all The --all option is useful when exploring the registry, but it adds every available component and its dependencies to src/components/ui. For most production projects, adding components as you need them keeps the codebase easier to understand and maintain.
If you want more variations than the default registry provides, browse the shadcn ui components collection for individual controls or use complete shadcn blocks as starting points for larger interface sections. Because the source is added to your project, you can adapt each example to the theme and conventions established during setup.
Because the generated files belong to your repository, commit any custom component changes before running commands with --overwrite.
Faster Setup Options
If you are starting a completely new project, shadcn/ui offers two shortcuts that can replace the manual setup in Steps 1 through 5.
Build a preset visually with shadcn/create
Open shadcn/create, choose your component base, style, colors, fonts, icons, radius, and other options, and then copy the generated Vite command.
It will look similar to:
pnpm dlx shadcn@latest init --preset [CODE] --template vite npx shadcn@latest init --preset [CODE] --template vite yarn dlx shadcn@latest init --preset [CODE] --template vite bunx --bun shadcn@latest init --preset [CODE] --template vite Replace [CODE] with the preset code generated by shadcn/create. The exact command may also include options such as --base, --monorepo, or --rtl.
Scaffold a Vite project from the terminal
You can also let the shadcn CLI create the Vite project directly:
pnpm dlx shadcn@latest init -t vite npx shadcn@latest init -t vite yarn dlx shadcn@latest init -t vite bunx --bun shadcn@latest init -t vite Follow the prompts to choose the project name and configuration.
Whichever shortcut you use, components are added in the same way:
pnpm dlx shadcn@latest add card npx shadcn@latest add card yarn dlx shadcn@latest add card bunx --bun shadcn@latest add card The manual route is still worth understanding because it is the process you need when adding shadcn/ui to a Vite application that already exists. For a framework-independent checklist, read How to Add shadcn/ui to an Existing Project.
Once the foundation is working, complete Shadcn templates can accelerate a new dashboard or landing page while preserving the same copy-and-customize workflow.
Monorepo projects
To scaffold a new monorepo, add the --monorepo flag:
pnpm dlx shadcn@latest init -t vite --monorepo npx shadcn@latest init -t vite --monorepo yarn dlx shadcn@latest init -t vite --monorepo bunx --bun shadcn@latest init -t vite --monorepo When adding components from a monorepo root, use -c to target the application workspace when necessary:
pnpm dlx shadcn@latest add card -c apps/web npx shadcn@latest add card -c apps/web yarn dlx shadcn@latest add card -c apps/web bunx --bun shadcn@latest add card -c apps/web The shadcn/ui Vite installation guide and CLI reference cover workspace targeting and the complete list of available commands.
How Tailwind CSS v4 Theming Works
Tailwind CSS v4 moves most configuration into CSS. After shadcn init, src/index.css typically contains several layers:
@import "tailwindcss"loads Tailwind CSS.- Additional imports load shadcn utilities and animations when required.
:rootcontains semantic values for the light theme..darkcontains the dark-theme values.@theme inlinemaps those values to Tailwind utilities such asbg-backgroundandtext-foreground.
A simplified token pair looks like this:
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
}
Components use semantic utilities instead of hard-coded colors:
<div className="bg-background text-foreground">Content</div>
Changing the underlying CSS variables updates every component that uses the corresponding semantic token. You do not need a tailwind.config.js file for this standard Tailwind CSS v4 setup.
The Shadcn Theme Generator provides a visual way to experiment with these tokens before applying them to src/index.css. If your team defines the visual system before implementation, the Shadcn Figma library can keep design decisions aligned with the components developers use.
If you want to generate and reuse a complete visual configuration instead of editing every token manually, our guide to shadcn/ui presets explains the preset workflow.
Common Setup Errors and Fixes
The CLI cannot resolve the @/* alias
Check all three alias locations:
tsconfig.jsontsconfig.app.jsonvite.config.ts
The paths must point to the same directory. Restart the editor and development server after changing TypeScript or Vite configuration.
Cannot find module ‘path’ inside vite.config.ts
Install the Node.js type definitions:
pnpm add -D @types/node npm install -D @types/node yarn add -D @types/node bun add -d @types/node Then confirm vite.config.ts imports path:
import path from "path";
Components render without styles
Confirm that src/index.css contains the Tailwind import:
@import "tailwindcss";
Also confirm src/main.tsx imports the stylesheet:
import "./index.css";
Finally, verify that tailwindcss() appears in the Vite plugins array.
The CLI cannot find the global CSS file
Open components.json and check the Tailwind CSS path:
{
"tailwind": {
"config": "",
"css": "src/index.css"
}
}
For Tailwind CSS v4, tailwind.config should remain an empty string. Update tailwind.css if you moved the stylesheet.
Utility classes work, but shadcn colors do not
This usually means Tailwind is running but the generated theme block is missing or was overwritten. Compare src/index.css with the output created by shadcn init, or rerun initialization after committing your current work so you can review the changes safely.
The page still shows Vite’s starter design
Remove the starter rules from src/index.css and any unused styles imported from src/App.css. Vite’s demo styles can constrain the root container, add unexpected spacing, or override the layout you are trying to build.
Frequently Asked Questions
Does shadcn/ui support Tailwind CSS v4?
- Yes. The current shadcn CLI can initialize Tailwind CSS v4 projects and generates components, CSS variables, and utilities that use the v4 configuration model. New components also use Tailwind CSS v4-compatible styles.
Do I need a tailwind.config.js file?
- No. A standard Tailwind CSS v4 and Vite project keeps its theme configuration in CSS. Leave
tailwind.configempty incomponents.jsonand pointtailwind.csstosrc/index.css.
Why does shadcn/ui require the @/* alias?
- The alias gives generated components stable import paths such as
@/lib/utilsand@/components/ui/button. The CLI needs the alias to know where to write files, TypeScript needs it for type checking, and Vite needs it to resolve those imports at runtime.
Can I use JavaScript instead of TypeScript?
- Yes. Start with Vite’s
reacttemplate instead ofreact-ts, create thejsconfig.jsonalias shown earlier, and choose JavaScript when the shadcn CLI asks how components should be generated. The Vite runtime alias is still required.
Key Takeaways
- Install and configure Tailwind CSS before running
shadcn initin an existing project. - Configure the
@/*alias in both TypeScript files and invite.config.ts. - Use the official
@tailwindcss/viteplugin with Tailwind CSS v4. - Keep the Tailwind config path empty for a standard Tailwind CSS v4 project.
- Theme values live in CSS variables and are mapped through
@theme inline. - shadcn/ui components are source files you own, not opaque package imports.
- Add components as you need them to keep
src/components/uimanageable.
Next Steps
- Add
card,dialog, andinput, then compose them into a small interface. - Set up dark mode by toggling the
darkclass; the generated CSS already contains the dark-theme values. - Open
button.tsx, change a variant or class, and see how source ownership works. - Swap a few
:roottheme values and watch every component using those tokens update.
Congratulations—shadcn/ui and Tailwind CSS v4 are now running in Vite!!! The setup work is complete, and each additional component is only one CLI command away.
For an editor-based workflow after setup, the shadcn/studio MCP server lets supported IDEs and AI tools explore components, blocks, and pages without leaving the development environment.
Resources
-
Vite: Getting Started
-
shadcn/ui: Vite Installation
-
shadcn/create
-
shadcn/ui CLI Reference
-
shadcn/ui Theming
-
Tailwind CSS: Installing with Vite
-
Tailwind CSS v4 Documentation
-
Reference article: Setting Up React 19 with Tailwind CSS v4 and shadcn/ui Without TypeScript
Happy building.