DEV Community

Darshan Bajgain
Darshan Bajgain

Posted on

🚀Setting Up (2025) Next.js 15 with ShadCN & Tailwind CSS v4 (No Config Needed) + Dark Mode

LightMode
DarkMode

With the release of Next.js 15 and Tailwind CSS v4, setting up a modern web project has never been easier. This guide walks you through setting up Next.js 15 with ShadCN UI and Tailwind CSS v4, leveraging the latest inline theming approach without needing tailwind.config.ts. We will also integrate dark mode with next-themes, ensuring a seamless experience.


🔧 Prerequisites

Before starting, ensure you have:
Node.js 18+ installed (Check with node -v)
npm or pnpm installed
Basic knowledge of Next.js & Tailwind CSS


1️⃣ Create a Next.js 15 App

Run the following command to initialize a TypeScript-based Next.js 15 project:

npx create-next-app@latest my-project --ts --tailwind --eslint --app
Enter fullscreen mode Exit fullscreen mode

🔹 --ts → Enables TypeScript

🔹 --tailwind → Auto-configures Tailwind CSS

🔹 --app → Uses the new App Router (recommended for Next.js 15)

Just follow steps in the terminal menu that will appear like this:

Need to install the following packages:
create-next-app@15.2.1
Ok to proceed? (y) y

✔ Would you like your code inside a `src/` directory? … No / Yes
✔ Would you like to use Turbopack for `next dev`? … No / Yes
✔ Would you like to customize the import alias (`@/*` by default)? … No / Yes
✔ What import alias would you like configured? … @/*
Creating a new Next.js app in /home/devd/my-project.

Using npm.

Initializing project with template: app-tw 


Installing dependencies:
- react
- react-dom
- next

Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- @tailwindcss/postcss
- tailwindcss
- eslint
- eslint-config-next
- @eslint/eslintrc

added 313 packages, and audited 314 packages in 1m

130 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Initialized a git repository.

Success! Created my-project at /home/devd/my-project

Enter fullscreen mode Exit fullscreen mode

2️⃣ Install ShadCN UI

ShadCN provides a collection of beautiful, accessible, and customizable UI components.

npx shadcn-ui@latest init
Enter fullscreen mode Exit fullscreen mode

Then install components (like all if you want)**:

npx shadcn@latest add 
Enter fullscreen mode Exit fullscreen mode
~$ cd my-project
~/my-project$ npx shadcn@latest init
Need to install the following packages:
shadcn-ui@0.9.5
Ok to proceed? (y) y

~/my-project$ npx shadcn@latest add
✔ Which components would you like to add? › accordion, alert, alert-dialog, aspect-ratio, avatar, badge, breadcrumb, button, calendar, card, carousel, chart, checkbox, collapsible, command, context-menu, dialog, drawer, dropdown-menu, form, hover-card, input, input-otp, label, menubar, navigation-menu, pagination, popover, progress, radio-group, resizable, scroll-area, select, separator, sheet, sidebar, skeleton, slider, sonner, switch, table, tabs, textarea, toggle, toggle-group, tooltip
✔ You need to create a components.json file to add components. Proceed? … yes
✔ Which color would you like to use as the base color? › Neutral
✔ Writing components.json.

It looks like you are using React 19. 
Some packages may fail to install due to peer dependency issues in npm (see https://ui.shadcn.com/react-19).

✔ How would you like to proceed? › Use --legacy-peer-deps
✔ Checking registry.
✔ Updating src/app/globals.css
  Installing dependencies.

It looks like you are using React 19. 
Some packages may fail to install due to peer dependency issues in npm (see https://ui.shadcn.com/react-19).

✔ How would you like to proceed? › Use --legacy-peer-deps
✔ Installing dependencies.
✔ Created 47 files:
  - src/components/ui/accordion.tsx
  - src/components/ui/alert.tsx
  - src/components/ui/alert-dialog.tsx
  - src/components/ui/button.tsx
  - src/components/ui/aspect-ratio.tsx
  - src/components/ui/avatar.tsx
  - src/components/ui/badge.tsx
  - src/components/ui/breadcrumb.tsx
  - src/components/ui/calendar.tsx
  - src/components/ui/card.tsx
  - src/components/ui/carousel.tsx
  - src/components/ui/chart.tsx
  - src/components/ui/checkbox.tsx
  - src/components/ui/collapsible.tsx
  - src/components/ui/command.tsx
  - src/components/ui/dialog.tsx
  - src/components/ui/context-menu.tsx
  - src/components/ui/drawer.tsx
  - src/components/ui/dropdown-menu.tsx
  - src/components/ui/form.tsx
  - src/components/ui/label.tsx
  - src/components/ui/hover-card.tsx
  - src/components/ui/input.tsx
  - src/components/ui/input-otp.tsx
  - src/components/ui/menubar.tsx
  - src/components/ui/navigation-menu.tsx
  - src/components/ui/pagination.tsx
  - src/components/ui/popover.tsx
  - src/components/ui/progress.tsx
  - src/components/ui/radio-group.tsx
  - src/components/ui/resizable.tsx
  - src/components/ui/scroll-area.tsx
  - src/components/ui/select.tsx
  - src/components/ui/separator.tsx
  - src/components/ui/sheet.tsx
  - src/components/ui/sidebar.tsx
  - src/components/ui/tooltip.tsx
  - src/hooks/use-mobile.ts
  - src/components/ui/skeleton.tsx
  - src/components/ui/slider.tsx
  - src/components/ui/sonner.tsx
  - src/components/ui/switch.tsx
  - src/components/ui/table.tsx
  - src/components/ui/tabs.tsx
  - src/components/ui/textarea.tsx
  - src/components/ui/toggle.tsx
  - src/components/ui/toggle-group.tsx
Enter fullscreen mode Exit fullscreen mode

3️⃣Configure Tailwind CSS v4 (No Config File Needed!)

Tailwind CSS v4 no longer requires tailwind.config.ts. Instead, we define variables inside global.css.

Modify app/globals.css

On your existing globals.css file you can add few more color variables like this

//rest of the code
:root {
  --background-primary: rgba(249, 250, 251, 1); 
  --background-secondary: rgba(18, 18, 18, 1);
  --text-primary: rgba(55, 65, 81, 1);
  --text-secondary: rgba(243, 244, 246, 1);
  --buttons: rgba(250, 204, 21, 1);
  --border-color: rgba(209, 213, 219, 1);
}

.dark {
  --background-primary: rgba(18, 18, 18, 1);
  --background-secondary: rgba(249, 250, 251, 1);
  --text-primary: rgba(243, 244, 246, 1);
  --text-secondary: rgba(55, 65, 81, 1);
}

//rest of the code

Enter fullscreen mode Exit fullscreen mode

Then on the @theme inline just simply assign those variable with prefix --color- to anyName you choose to use inside Tailwind classes in your components:

@import "tailwindcss";
@import "tailwindcss-animate";

@custom-variant dark (&:is(.dark *));

@theme inline {
  // rest of the code ......
  --color-buttons: var(--buttons);
  --color-textSecondary: var(--text-secondary);
  --color-textPrimary: var(--text-primary);
  --color-backgroundSecondary: var(--background-secondary);
  --color-backgroundPrimary: var(--background-primary);
  --color-borderColor: var(--border-color);
}
Enter fullscreen mode Exit fullscreen mode

Eg: In your any component, you have this element and you can use the variables inside the tailwind classes as text-textPrimary

<h1 className="text-sm text-textPrimary"> Hello </h1>
Enter fullscreen mode Exit fullscreen mode

🚀 This allows you to use Tailwind CSS variables without a config file!


4️⃣ Enable Dark Mode with next-themes

Install next-themes

npm install next-themes
Enter fullscreen mode Exit fullscreen mode

or

npm install next-themes --legacy-peer-deps
Enter fullscreen mode Exit fullscreen mode

Create theme-provider.tsx in components/

"use client";

import { ThemeProvider as NextThemesProvider } from "next-themes";
import { useEffect, useState } from "react";

export function ThemeProvider({ children }: { children: React.ReactNode }) {
    const [mounted, setMounted] = useState(false);

    // Fix hydration issue (ensures the theme is loaded on the client)
    useEffect(() => {
        setMounted(true);
    }, []);

    if (!mounted) {
        return <>{children}</>; // Prevents mismatch between server & client rendering
    }

    return (
        <NextThemesProvider attribute="class" defaultTheme="system" enableSystem>
            {children}
        </NextThemesProvider>
    );
}
Enter fullscreen mode Exit fullscreen mode

Create theme-toggle.tsx

"use client";

import { useTheme } from "next-themes";
import { useEffect, useState } from "react";

export function ThemeToggle() {
    const { setTheme, resolvedTheme } = useTheme();
    const [mounted, setMounted] = useState(false);

    // Fix hydration issue
    useEffect(() => {
        setMounted(true);
    }, []);

    if (!mounted) {
        return null; // Avoids hydration mismatch on SSR
    }

    return (
        <button
            className="fixed bottom-4 right-4 p-2 bg-buttons text-textPrimary rounded"
            onClick={() => setTheme(resolvedTheme === "dark" ? "light" : "dark")}
        >
            {resolvedTheme === "dark" ? "Light Mode" : "Dark Mode"}
        </button>
    );
}

Enter fullscreen mode Exit fullscreen mode

Modify layout.tsx to Use Theme Provider

import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "../../theme/theme-provider";
import { ThemeToggle } from "../../theme/theme-toggle";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
        <ThemeProvider>
          {children}
          <ThemeToggle />
        </ThemeProvider>
      </body>
    </html>
  );
}

Enter fullscreen mode Exit fullscreen mode

** 5️⃣ Run the Project**

Finally, start the Next.js development server:

npm run dev
Enter fullscreen mode Exit fullscreen mode

Your Next.js 15 + Tailwind v4 + ShadCN UI project is now ready! 🎉


🎯 Why This Setup is Awesome?

No Tailwind Config File Needed (Everything inline in globals.css)

Modern UI Components with ShadCN

Dark Mode Support with next-themes

Scalable & Performant (Next.js 15 App Router)

🚀 Now you have a fully functional modern Next.js stack with the latest Tailwind CSS v4 features! Let me know if you have any questions or want improvements. Happy coding! 🎨🔥

Top comments (0)