Docs
Installation

Installation

Add dependencies to your project manually.

Create project

First, create a new Next.js or React.js project using create-next-app:

npx create-next-app@latest my-project --typescript --eslint --app

or Install React.js via Vite:

npm create vite@latest my-react-app -- --template react

Add Tailwind CSS (v4)

I use Tailwind CSS v4. You need to install Tailwind CSS in your project.

If you are using Tailwind v3, then I recommend you to upgrade to v4 by using the following command:

npx @tailwindcss/upgrade

or install shadcn/ui with tailwindcss v4:

npx shadcn@latest init

Add dependencies

Add the following dependencies to your project:

npm install framer-motion tailwindcss-animate class-variance-authority clsx tailwind-merge

Add icon library

For Icons, install the following dependencies:

npm install lucide-react @radix-ui/react-icons

Configure path aliases

I use the @ alias. This is how I configure it in tsconfig.json:

tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"]
    }
  }
}

The @ alias is a preference. You can use other aliases if you want.

If you use a different alias such as ~, you'll need to update import statements when adding components.

Configure styles

Add the following to your globals.css file. You can learn more about using CSS variables for theming.

globals.css
@import "tailwindcss";
 
@plugin 'tailwindcss-animate';
 
@custom-variant dark (&:where(.dark, .dark *));
 
:root {
  --background: hsl(0 0% 100%);
  --foreground: hsl(240 10% 3.9%);
  --card: hsl(0 0% 100%);
  --card-foreground: hsl(240 10% 3.9%);
  --popover: hsl(0 0% 100%);
  --popover-foreground: hsl(240 10% 3.9%);
  --primary: hsl(240 5.9% 10%);
  --primary-foreground: hsl(0 0% 98%);
  --secondary: hsl(240 4.8% 95.9%);
  --secondary-foreground: hsl(240 5.9% 10%);
  --muted: hsl(240 4.8% 95.9%);
  --muted-foreground: hsl(240 3.8% 46.1%);
  --accent: hsl(240 4.8% 95.9%);
  --accent-foreground: hsl(240 5.9% 10%);
  --destructive: hsl(0 84.2% 60.2%);
  --destructive-foreground: hsl(0 0% 98%);
  --border: hsl(240 5.9% 90%);
  --input: hsl(240 5.9% 90%);
  --ring: hsl(240 5% 64.9%);
  --chart-1: hsl(41 22.2% 64.6%);
  --chart-2: hsl(185 11.8% 60%);
  --chart-3: hsl(227 7% 39.8%);
  --chart-4: hsl(84 18.9% 82.8%);
  --chart-5: hsl(70 18.8% 76.9%);
  --radius: 0.625rem;
  --sidebar: hsl(0 0% 98.5%);
  --sidebar-foreground: hsl(0 0% 14.5%);
  --sidebar-primary: hsl(0 0% 20.5%);
  --sidebar-primary-foreground: hsl(0 0% 98.5%);
  --sidebar-accent: hsl(0 0% 97%);
  --sidebar-accent-foreground: hsl(0 0% 20.5%);
  --sidebar-border: hsl(0 0% 92.2%);
  --sidebar-ring: hsl(0 0% 70.8%);
}
 
.dark {
  --background: hsl(0 0% 0%);
  --foreground: hsl(0 0% 98%);
  --card: hsl(0 0% 0%);
  --card-foreground: hsl(0 0% 98%);
  --popover: hsl(0 0% 0%);
  --popover-foreground: hsl(0 0% 98%);
  --primary: hsl(0 0% 98.5%);
  --primary-foreground: hsl(240 5.9% 10%);
  --secondary: hsl(240 3.7% 15.9%);
  --secondary-foreground: hsl(0 0% 98%);
  --muted: hsl(240 3.7% 15.9%);
  --muted-foreground: hsl(240 5% 64.9%);
  --accent: hsl(240 3.7% 15.9%);
  --accent-foreground: hsl(0 0% 98%);
  --destructive: hsl(0 62.8% 30.6%);
  --destructive-foreground: hsl(0 85.7% 97.3%);
  --border: hsl(240 3.7% 15.9%);
  --input: hsl(240 3.7% 15.9%);
  --ring: hsl(240 4.9% 83.9%);
  --chart-1: hsl(264 24.3% 48.8%);
  --chart-2: hsl(162 17% 69.6%);
  --chart-3: hsl(70 18.8% 76.9%);
  --chart-4: hsl(304 26.5% 62.7%);
  --chart-5: hsl(16 24.6% 64.5%);
  --sidebar: hsl(240 3.7% 15.9%);
  --sidebar-foreground: hsl(0 0% 98.5%);
  --sidebar-primary: hsl(264 24.3% 48.8%);
  --sidebar-primary-foreground: hsl(0 0% 98.5%);
  --sidebar-accent: hsl(240 3.7% 15.9%);
  --sidebar-accent-foreground: hsl(0 0% 98.5%);
  --sidebar-border: hsl(240 3.7% 15.9%);
  --sidebar-ring: hsl(240 3.7% 15.9%);
}
 
@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);
  --color-popover: var(--popover);
  --color-popover-foreground: var(--popover-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-accent: var(--accent);
  --color-accent-foreground: var(--accent-foreground);
  --color-destructive: var(--destructive);
  --color-destructive-foreground: var(--destructive-foreground);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --color-chart-1: var(--chart-1);
  --color-chart-2: var(--chart-2);
  --color-chart-3: var(--chart-3);
  --color-chart-4: var(--chart-4);
  --color-chart-5: var(--chart-5);
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);
  --color-sidebar: var(--sidebar);
  --color-sidebar-foreground: var(--sidebar-foreground);
  --color-sidebar-primary: var(--sidebar-primary);
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
  --color-sidebar-accent: var(--sidebar-accent);
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
  --color-sidebar-border: var(--sidebar-border);
  --color-sidebar-ring: var(--sidebar-ring);
}
 
@layer base {
  * {
    @apply border-border outline-ring/50;
  }
  body {
    @apply bg-background text-foreground;
  }
}

Add a cn helper

I use a cn helper to make it easier to conditionally add Tailwind CSS classes. Here's how I define it in lib/utils.ts:

lib/utils.ts
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
 
export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

That's it

You can now start adding components to your project.