How to Set Up Shadcn UI in a Next.js 15 Project (2026 Guide)
Step-by-step guide to installing and configuring Shadcn UI in a fresh Next.js 15 project. Covers project creation, Shadcn initialization, Tailwind config, adding components, theming, and project structure.
SERP Blocks Team
Product
Starting a new Next.js project and want to use Shadcn UI for your component library? This guide walks through every step — from creating the project to adding your first components and customizing the theme. No prior Shadcn experience required.
By the end, you'll have a working Next.js 15 project with Shadcn UI fully configured, a handful of components installed, and a clear understanding of how the system works so you can build on it confidently.
Prerequisites
Before starting, make sure you have the following installed:
Node.js 18.18 or later — check with
node -vA package manager — npm, yarn, pnpm, or bun all work. This guide uses npm, but every command has equivalents for other managers
A code editor — VS Code with the Tailwind CSS IntelliSense extension is the recommended setup
If you're running Node 20 or later (the current LTS as of 2026), you're good to go.
Step 1: Create a New Next.js 15 Project
Open your terminal and run:
npx create-next-app@latest my-shadcn-appThe CLI will ask you a series of questions. Here are the recommended answers for a Shadcn UI project:
Would you like to use TypeScript? Yes
Would you like to use ESLint? Yes
Would you like to use Tailwind CSS? Yes
Would you like your code inside a `src/` directory? Yes
Would you like to use App Router? Yes
Would you like to use Turbopack for next dev? Yes
Would you like to customize the import alias? NoThe important ones are TypeScript (Shadcn components are written in TypeScript), Tailwind CSS (required — Shadcn UI is styled entirely with Tailwind), and App Router (the standard routing approach in Next.js 15).
After the CLI finishes, move into the project directory:
cd my-shadcn-appVerify everything works by starting the dev server:
npm run devOpen http://localhost:3000 and you should see the default Next.js welcome page. Stop the server with Ctrl+C once you've confirmed it works.
Step 2: Initialize Shadcn UI
With your Next.js project created, run the Shadcn CLI:
npx shadcn@latest initThis command detects your project configuration (TypeScript, Tailwind, App Router) and asks a few setup questions:
Which style would you like to use? New York
Which color would you like to use as the base color? Neutral
Would you like to use CSS variables for theming? YesStyle — Shadcn offers two visual styles: "Default" and "New York." New York has slightly more refined spacing and borders. Both are fully customizable after setup, so pick whichever appeals to you. New York is the more popular choice in 2026.
Base color — This sets the neutral palette (backgrounds, borders, text). Options include Slate, Gray, Zinc, Neutral, and Stone. They're all close variations of gray. Neutral is a safe default that works with any accent color.
CSS variables — Always say yes. CSS variables make theming dramatically easier and enable dark mode with a single class toggle.
After initialization, the CLI creates and modifies several files:
What Changed in Your Project
components.json — This is Shadcn's configuration file. It tells the CLI where to put components, which style to use, and how imports are aliased. You rarely need to edit this manually.
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/globals.css",
"baseColor": "neutral",
"cssVariables": true
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
}
}src/app/globals.css — Updated with CSS custom properties for the color theme. You'll see variables like --background, --foreground, --primary, --secondary, --accent, --muted, --destructive, and more — each defined for both light and dark mode.
src/lib/utils.ts — A utility file with the cn() function, which merges Tailwind classes using clsx and tailwind-merge:
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}You'll use cn() constantly when working with Shadcn components. It lets you conditionally apply classes without worrying about Tailwind class conflicts.
src/components/ui/ — This directory is created (empty for now). Every Shadcn component you add will be placed here.
Step 3: Add Your First Components
Shadcn UI doesn't install all components at once. You add only what you need, when you need it. This keeps your bundle lean and your components/ui directory manageable.
Let's add a few foundational components:
npx shadcn@latest add button
npx shadcn@latest add card
npx shadcn@latest add input
npx shadcn@latest add labelOr add multiple at once:
npx shadcn@latest add button card input labelEach command copies the component source code into src/components/ui/. After running these, your directory looks like:
src/
components/
ui/
button.tsx
card.tsx
input.tsx
label.tsx
lib/
utils.tsThese are real .tsx files in your project — not imported from node_modules. Open button.tsx and you'll see the full component source, built on class-variance-authority for variant management and the cn() utility for class merging. You can read, understand, and modify every line.
Step 4: Use a Component
Let's replace the default Next.js homepage with something that uses Shadcn components. Open src/app/page.tsx and replace its contents:
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
export default function Home() {
return (
<main className="flex min-h-screen items-center justify-center p-4">
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle>Welcome</CardTitle>
<CardDescription>
Your Next.js + Shadcn UI project is ready.
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="you@example.com" />
</div>
<Button className="w-full">Get Started</Button>
</CardContent>
</Card>
</main>
);
}Start the dev server again with npm run dev and you'll see a centered card with an email input and a button. Clean, accessible, and styled with your Tailwind theme.
Step 5: Understand the Project Structure
Here's how a typical Next.js + Shadcn UI project is organized:
src/
app/
layout.tsx # Root layout with fonts, metadata, theme provider
page.tsx # Homepage
globals.css # Tailwind base styles + CSS variables
components/
ui/ # Shadcn UI primitives (button, card, dialog, etc.)
[feature]/ # Your custom components that use the primitives
lib/
utils.ts # cn() utility and other shared helpers
hooks/ # Custom React hooksThe separation between components/ui (Shadcn primitives) and your custom components is important. The ui directory contains the building blocks — buttons, inputs, dialogs, dropdowns. Your feature components compose those primitives into larger, application-specific UI.
For example, a components/contact-form.tsx might import Button, Input, Textarea, and Select from components/ui/ and compose them into a complete contact form with your specific fields and validation.
Step 6: Set Up Dark Mode
Shadcn UI supports dark mode through CSS variables, but you need a theme provider to toggle between modes. The most common approach uses next-themes:
npm install next-themesCreate a theme provider component:
// src/components/theme-provider.tsx
"use client";
import { ThemeProvider as NextThemesProvider } from "next-themes";
export function ThemeProvider({
children,
...props
}: React.ComponentProps<typeof NextThemesProvider>) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}Wrap your app layout with the provider:
// src/app/layout.tsx
import { ThemeProvider } from "@/components/theme-provider";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
{children}
</ThemeProvider>
</body>
</html>
);
}Now add a theme toggle button. First install the dropdown menu component:
npx shadcn@latest add dropdown-menuThen create the toggle:
// src/components/theme-toggle.tsx
"use client";
import { Moon, Sun } from "lucide-react";
import { useTheme } from "next-themes";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export function ThemeToggle() {
const { setTheme } = useTheme();
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme("light")}>Light</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("dark")}>Dark</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("system")}>System</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}Every Shadcn component respects the CSS variables, so switching between light and dark mode updates your entire UI instantly — no extra configuration per component.
Step 7: Customize the Theme
The CSS variables in globals.css control the entire visual identity of your project. Here's what the key variables do:
| Variable | Purpose |
--background | Page background color |
--foreground | Default text color |
--primary | Primary action color (buttons, links) |
--primary-foreground | Text color on primary backgrounds |
--secondary | Secondary/subtle action color |
--muted | Muted backgrounds (disabled states, subtle sections) |
--accent | Accent highlights (hover states, active items) |
--destructive | Error/danger color (delete buttons, error messages) |
--border | Default border color |
--ring | Focus ring color |
--radius | Global border radius |
To change your theme, you only need to update these variables. For example, to use a blue primary color instead of the default, update the --primary values in your CSS:
@layer base {
:root {
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
}
.dark {
--primary: 217.2 91.2% 59.8%;
--primary-foreground: 222.2 84% 4.9%;
}
}The Shadcn UI Themes page provides a visual theme builder where you can pick colors and copy the generated CSS variables directly into your project.
Step 8: Add More Components as Needed
Shadcn UI offers over 50 primitive components. Here are the ones you're most likely to need early on, grouped by use case:
Layout and Navigation:
npx shadcn@latest add navigation-menu sheet separatorForms:
npx shadcn@latest add form select textarea checkbox radio-group switchFeedback:
npx shadcn@latest add alert dialog sonner tooltipData Display:
npx shadcn@latest add table badge avatar tabs accordionRemember — only add what you need. Each component is independent. Adding dialog doesn't require adding button first (though you'll almost certainly want both). The CLI handles peer dependencies between Shadcn components automatically.
Common Issues and Fixes
"Module not found" After Adding a Component
If you see import errors after running npx shadcn@latest add, make sure your tsconfig.json has the correct path aliases:
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}This should be set up automatically by create-next-app, but it's worth verifying if imports break.
Tailwind Classes Not Applying
Make sure your tailwind.config.ts includes the correct content paths. After Shadcn initialization, it should include:
content: [
"./src/**/*.{js,ts,jsx,tsx,mdx}",
],If you've moved components to a non-standard directory, update this array to match.
Components Look Unstyled
Check that globals.css is imported in your root layout (src/app/layout.tsx). The CSS variable definitions live there, and without them, all the Tailwind utility classes like bg-primary and text-muted-foreground resolve to nothing.
Dark Mode Not Working
Verify three things:
next-themesis installed and theThemeProviderwraps your layoutThe
ThemeProviderusesattribute="class"(notattribute="data-theme")Your
htmltag hassuppressHydrationWarningto avoid Next.js hydration errors
What Comes After Setup
Once your project is configured and you're comfortable adding components, the next step is building actual page sections — hero areas, feature grids, navigation bars, footers, forms, and everything else that makes up a real website.
This is where the gap between "components" and "blocks" becomes obvious. Shadcn UI gives you the primitives: Button, Card, Input, Dialog. But it doesn't give you a complete hero section with a headline, subtext, CTA buttons, and a background image. It doesn't give you a pricing table with three tiers and a toggle between monthly and annual billing. It doesn't give you a footer with columns of links, social icons, and a newsletter signup.
Building those page sections from Shadcn primitives is entirely possible — that's what the primitives are for. But it takes time, and most projects need dozens of these sections.
SERP Blocks is a library of over 1,200 pre-built page sections — all built with Shadcn UI and Tailwind CSS, designed to drop directly into the kind of Next.js project you just set up. The library covers 50+ categories: 81 hero sections, 132 feature sections, 110 card components, 21 pricing pages, 17 navbar designs, 21 footer layouts, 33 contact forms, 20 dashboard layouts, and dozens more categories.
Each block is a self-contained React component built with the same Shadcn UI components you just installed — Button, Card, Input, Badge, Avatar, and so on. Because they use the same CSS variable theming system, they automatically match your project's color scheme and dark mode settings. Copy a block into your project, and it works immediately with your existing Shadcn setup.
60 blocks are free. The full Pro library is a one-time purchase — no subscription — with lifetime access to every current block and every block added in the future.
Quick Reference
Here's the complete setup sequence in one place for easy reference:
# 1. Create Next.js project
npx create-next-app@latest my-shadcn-app
cd my-shadcn-app
# 2. Initialize Shadcn UI
npx shadcn@latest init
# 3. Add components you need
npx shadcn@latest add button card input label
# 4. Install dark mode support
npm install next-themes
# 5. Start building
npm run devFive commands and you're ready to build. The entire setup takes under five minutes on a decent internet connection. From here, you have a production-ready foundation — TypeScript, Tailwind CSS, accessible components, dark mode, and a theming system that scales from a side project to a full SaaS application.