DEV Community

Cover image for πŸš€ React + Vite + Tailwind CSS + Shadcn UI Setup (vanillaJS)
Nabin Kandel
Nabin Kandel

Posted on

πŸš€ React + Vite + Tailwind CSS + Shadcn UI Setup (vanillaJS)

A complete step-by-step guide to quickly set up **React + Vite + Tailwind CSS + Shadcn UI* with clean @/... alias imports β€” no TypeScript required!*

⏱️ Time to complete: ~10 minutes

🎯 Result: Production-ready React app with beautiful, accessible components


🧩 Step 1: Create a Vite + React Project

Scaffold your new project with Vite:

npm create vite@latest my-app
cd my-app
Enter fullscreen mode Exit fullscreen mode

When prompted, select:
Option | Choice
Framework | React
Variant | JavaScript

βœ… Vite will generate a lean, fast React starter with HMR (Hot Module Replacement) out of the box.


πŸŒ€ Step 2: Install Dependencies

Install core packages and Tailwind's official Vite plugin:

npm install
npm install tailwindcss @tailwindcss/vite
Enter fullscreen mode Exit fullscreen mode
Package Purpose
tailwindcss Utility-first CSS framework
@tailwindcss/vite First-party Vite plugin for Tailwind (no PostCSS config needed!)

🎨 Step 3: Configure vite.config.js

Replace the entire contents of vite.config.js with:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
import path from "path";

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    tailwindcss(),
    react({
      babel: {
        plugins: [["babel-plugin-react-compiler"]], // βœ… Optional: React Compiler for perf
      },
    }),
  ],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"), // βœ… Enable @/ imports
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

πŸ” Why This Matters:

  • @tailwindcss/vite β†’ Compiles Tailwind at build time (faster than PostCSS!)
  • @ alias β†’ Import like import Button from "@/components/ui/button" instead of ../../../components/ui/button 🧹

βš™οΈ Step 4: Create jsconfig.json for Editor Support

At your project root, create jsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Benefits:

  • βœ… VS Code autocomplete for @/ imports
  • βœ… ESLint/Prettier understand your alias paths
  • βœ… No more "Cannot find module" warnings πŸ‘»

πŸͺ„ Step 5: Import Tailwind in Your CSS

Open or create src/index.css and add:

@import "tailwindcss";
Enter fullscreen mode Exit fullscreen mode

πŸŽ‰ That's it! With @tailwindcss/vite, you don't need @tailwind base/components/utilities β€” the plugin handles it automatically.

(Optional) Clean up default styles:

Delete or empty src/App.css to avoid conflicting styles.


🌈 Step 6: Initialize Shadcn UI

Run the Shadcn CLI to set up your component library:

npx shadcn@latest init
Enter fullscreen mode Exit fullscreen mode

Follow the prompts:
| Question | Recommended Choice |
|----------|-------------------|
| Style | New York or Default |
| Base color | Slate (neutral & accessible) |
| CSS variables | Yes (for theming) |

Then add your first components:

npx shadcn@latest add button card input
Enter fullscreen mode Exit fullscreen mode

βœ… Components land in src/components/ui/ β€” fully customizable, accessible, and Tailwind-powered.


πŸ’» Step 7: Test Your Setup

Open src/App.jsx and replace with:

import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";

export default function App() {
  return (
    <div className="flex min-h-screen items-center justify-center bg-gray-50 p-4">
      <Card className="w-full max-w-md">
        <CardHeader>
          <CardTitle className="text-center">πŸŽ‰ Setup Successful!</CardTitle>
        </CardHeader>
        <CardContent className="flex flex-col gap-4">
          <p className="text-center text-gray-600">
            You're now running React + Vite + Tailwind + Shadcn UI.
          </p>
          <Button className="w-full">Click Me</Button>
          <Button variant="outline" className="w-full">
            Secondary Action
          </Button>
        </CardContent>
      </Card>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Then start the dev server:

npm run dev
Enter fullscreen mode Exit fullscreen mode

πŸ”— Visit http://localhost:5173 β€” you should see a beautifully styled card with Shadcn buttons!


βœ… Final Project Structure

my-app/
β”œβ”€β”€ public/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   └── ui/          # 🎨 Shadcn components (button, card, input...)
β”‚   β”œβ”€β”€ App.jsx          # 🏠 Main app component
β”‚   β”œβ”€β”€ index.css        # 🎨 Tailwind import
β”‚   └── main.jsx         # ⚑ React entry point
β”œβ”€β”€ index.html
β”œβ”€β”€ vite.config.js       # βš™οΈ Vite + Tailwind + alias config
β”œβ”€β”€ jsconfig.json        # 🧠 Editor alias support
β”œβ”€β”€ tailwind.config.js   # 🎨 Auto-generated by Shadcn (optional to tweak)
β”œβ”€β”€ package.json
└── ...
Enter fullscreen mode Exit fullscreen mode

🧭 Pro Tip: Keep src/components/ui/ for Shadcn primitives, and create src/components/ for your custom composables (e.g., UserProfile.jsx, NavBar.jsx).


πŸ› οΈ Troubleshooting Quick Fixes

Issue Solution
❌ @/ imports not working Restart VS Code; ensure jsconfig.json is at root
❌ Tailwind classes not applying Verify @import "tailwindcss" is in index.css
❌ Shadcn components look unstyled Check that index.css is imported in main.jsx
❌ Vite server won't start Run npm run dev -- --force to clear HMR cache
❌ Button has no hover effect Ensure tailwind.config.js includes content paths (Shadcn auto-generates this)

πŸ§ͺ Bonus: Add a Dark Mode Toggle (Optional)

Shadcn supports theming out of the box! Add this to src/App.jsx:

import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";

export default function App() {
  const [dark, setDark] = useState(false);

  useEffect(() => {
    document.documentElement.classList.toggle("dark", dark);
  }, [dark]);

  return (
    <div className="flex min-h-screen flex-col items-center justify-center bg-background text-foreground transition-colors">
      <Button onClick={() => setDark(!dark)} variant="outline">
        {dark ? "β˜€οΈ Light Mode" : "πŸŒ™ Dark Mode"}
      </Button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

πŸŒ— Requires darkMode: "class" in tailwind.config.js (Shadcn sets this by default).


πŸ”— Helpful Resources


🎯 Key Takeaways

  • βœ… Vite = Blazing-fast dev server & build
  • βœ… @tailwindcss/vite = Simpler Tailwind setup (no PostCSS!)
  • βœ… @/ aliases = Cleaner, scalable imports
  • βœ… Shadcn UI = Production-ready, accessible components β€” you own the code
  • βœ… JavaScript-first = No TypeScript overhead for quick prototyping

πŸ™Œ If this guide helped you ship faster, give it a ❀️, share it with your team, or drop a comment with what you're building!

Top comments (0)