← All guides

Claude Code for Frontend: Next.js, Tailwind, shadcn/ui Patterns

How to use Claude Code for Next.js 15 App Router development — component generation, Tailwind styling, shadcn/ui integration, server vs client component.

Claude Code for Frontend: Next.js, Tailwind, shadcn/ui Patterns

Claude Code accelerates Next.js 15 App Router development by generating complete page components, wiring server data fetching, and handling Tailwind + shadcn/ui patterns accurately. The key is giving Claude Code a well-structured CLAUDE.md with your stack details, then using targeted component prompts. This guide covers the CLAUDE.md setup, component generation patterns, server vs client component decisions, and the common pitfalls.


CLAUDE.md Setup for Next.js Projects

A good CLAUDE.md makes every prompt 3× more accurate — Claude Code knows your routing conventions, component library, and type patterns without you having to repeat them.

# Project: [Your App Name]

Next.js 15 App Router, TypeScript strict, Tailwind CSS, shadcn/ui.

## Tech Stack
- Framework: Next.js 15 (App Router, no Pages Router)
- Language: TypeScript strict mode (no `any`)
- Styling: Tailwind CSS v4
- Components: shadcn/ui (components in `components/ui/`)
- Icons: Lucide React
- DB: Drizzle ORM + Neon PostgreSQL
- Auth: Clerk
- State: React Query (server state) + Zustand (client state)

## Component Conventions
- Server Components by default; add `"use client"` only when needed
- shadcn components are pre-installed — import from `@/components/ui/`
- Custom components in `components/` (not `components/ui/`)
- Page files: `app/[route]/page.tsx`
- Layout files: `app/[route]/layout.tsx`

## Data Fetching
- Server Components: `async/await` directly with Drizzle
- Client Components: React Query (`useQuery`, `useMutation`)
- API routes in `app/api/`

## TypeScript Patterns
- Infer types from Drizzle schema (don't redeclare)
- Use `type` not `interface` for simple objects
- Error types: `{ code: string; message: string }`

## Dev Commands
```bash
bun run dev        # Dev server
bun run build      # Production build
bun run typecheck  # Type check
npx shadcn add [component]  # Add shadcn component

---

## Generating Complete Page Components

### The pattern that works

Claude Code generates better components when you specify: route, data source, UI components, and behavior.

**Weak prompt:**

"Create a dashboard page"


**Strong prompt:**

"Create app/dashboard/page.tsx — a server component that:


Claude Code generates the full page, a separate `CostChart.tsx` client component, and skeleton placeholders.

---

## Server vs Client Component Decisions

Claude Code handles this well if you establish the pattern in CLAUDE.md. For clarity, you can also state it explicitly in prompts:

"The parent page is a server component. Extract only the interactive parts (the date picker, the filter dropdown) into a 'use client' component."


### Quick decision guide for your prompts

| Needs | Component type |
|-------|--------------|
| DB query, auth check | Server Component |
| `useState`, `useEffect` | Client Component |
| onClick handlers | Client Component |
| Static display | Server Component |
| External API fetch at request time | Server Component |
| Browser APIs (localStorage, etc.) | Client Component |

**Best practice prompt pattern:**

"Keep this as a server component. Put the toggle button logic in a separate ClientToggle.tsx with 'use client'."


---

## shadcn/ui Component Patterns

### Installing before prompting

Claude Code generates shadcn imports but won't run `npx shadcn add` unless you tell it to. If you know you need a new component:

"I need a DataTable with sorting and pagination. First run npx shadcn add table if it's not installed, then generate app/users/components/UsersTable.tsx using shadcn Table."


### Commonly used shadcn components with Claude Code

**Forms with validation:**

"Create a settings form at components/SettingsForm.tsx:


**Data tables:**

"Create a users data table with:


**Modals/dialogs:**

"Add an invite team member dialog to app/team/page.tsx:


---

## Tailwind Patterns That Work Well

### Be specific about layout

Vague styling prompts get inconsistent results:

**Weak:**

"Make the layout look nice"


**Strong:**

"Two-column layout: sticky left sidebar (w-64, border-r) with nav links, main content area (flex-1, overflow-y-auto, p-6). On mobile (< md), hide sidebar and show hamburger menu."


### Responsive design prompts

"Responsive card grid:


### Dark mode support

If your project uses dark mode, add to CLAUDE.md:
```markdown
## Styling Conventions
Dark mode is enabled via `class` strategy.
Always add dark: variants: `bg-white dark:bg-gray-900`
Use semantic color tokens from tailwind.config.ts when possible.

Then prompts like "add dark mode support to this component" work accurately.


Data Fetching Patterns

Server Component data fetching

"Create app/orders/page.tsx as a server component:
- Query orders table with Drizzle: last 50 orders, joined with users table
- Pass data to OrdersTable client component as props
- Wrap OrdersTable in Suspense with OrdersTableSkeleton fallback
- No useEffect — all fetching happens at the page level"

React Query for client-side data

"Add real-time polling to the dashboard:
- useQuery hook to fetch /api/usage/current every 30 seconds
- Show 'Last updated: X seconds ago' in the card footer
- Invalidate query on manual refresh button click"

Server Actions for mutations

"Replace the API route handler with a server action:
- Move POST /api/users/create logic to actions/users.ts
- Export `createUser` async function with 'use server'
- Form submits using useActionState hook
- Return { success: boolean; error?: string } shape"

Common Pitfalls and Fixes

Pitfall 1: "use client" at the wrong level

Claude Code sometimes adds "use client" to parent components unnecessarily, making server data fetching impossible.

Fix prompt:

"Remove 'use client' from the page component. Keep the parent a server 
component. Only the [ComponentName] that uses onClick needs 'use client' —
extract it to a separate file."

Pitfall 2: Missing Suspense boundaries

Generated components sometimes render without loading states.

Preventive prompt:

"For every async data fetch, add a corresponding Suspense boundary with
a skeleton component. Generate the skeleton too."

Pitfall 3: Incorrect shadcn import paths

Occasionally Claude Code imports from the wrong path.

Preventive CLAUDE.md addition:

## shadcn Import Paths
All shadcn components: `import { X } from "@/components/ui/x"`
Never import from "shadcn/ui" directly.

Pitfall 4: Forgetting error boundaries

"Add an error boundary to the data fetching section:
create app/dashboard/error.tsx with a simple 'Something went wrong' 
retry UI."

Full Page Generation Example

This prompt generates a complete, production-ready page:

"Create the billing management page at app/dashboard/billing/page.tsx:

Server Component. Fetch:
- Current subscription plan from users.plan column
- Usage this billing period (sum of usageRecords.totalCost for current month)
- Next billing date from Polar subscription API

UI Layout:
- Page header: 'Billing & Usage' with Plan badge (Free/Starter/Pro)
- Current Plan card: plan name, monthly price, features list, Upgrade CTA
  (if Free: Upgrade button linking to Polar checkout)
  (if paid: Manage Subscription button)
- Usage this period card: bar showing $X of $Y limit
- Payment history table: last 6 invoices (date, amount, status, download PDF link)
  (mock data if Polar integration not available)

Components:
- Extract <UsageMeter /> as client component (animated bar)
- Use shadcn Card, Table, Badge, Button
- Skeleton loading states for all three data sections

Types: infer from Drizzle schema, no manual redeclaration."

Speed Benchmarks: With vs Without Claude Code

Informal benchmarks on a Next.js SaaS project:

Task Manual With Claude Code
New CRUD page (list + form) 3-4 hours 20-30 minutes
Add shadcn DataTable with filters 2 hours 10-15 minutes
Responsive layout with dark mode 1.5 hours 15 minutes
Form validation + error handling 1 hour 10 minutes
Loading skeletons for entire page 45 min 5 minutes

Average: 5-8× faster for UI work when prompts are well-specified.


Frequently Asked Questions

Does Claude Code understand Tailwind v4? Yes. Add the Tailwind version to CLAUDE.md. Some older Tailwind v3 syntax (like divide-*) changed in v4 — being explicit prevents outdated patterns.

Can Claude Code install missing npm packages? Yes, if you give it permission. Add Bash(npm install *) or Bash(bun add *) to your permissions.allow in .claude/settings.json.

How do I handle Storybook alongside Claude Code? Add to CLAUDE.md: "For every new component, also create a .stories.tsx file using Storybook CSF3 format." Claude Code will generate stories alongside components.

Does it handle Next.js 15 breaking changes from 14? Generally yes — App Router patterns, async params, etc. Specify your Next.js version in CLAUDE.md to prevent it from using Pages Router patterns.

Can Claude Code run the dev server and check for visual errors? No — Claude Code operates in terminal and can't see the browser. Run the dev server yourself, screenshot issues, and describe them to Claude Code.


Related Guides


Take It Further

Power Prompts 300: Claude Code Productivity Patterns — Section 5 covers Frontend Patterns: 60 Next.js + Tailwind + shadcn prompts that generate production-ready components, including the full CLAUDE.md template for SaaS apps and the responsive layout patterns that work consistently.

→ Get Power Prompts 300 — $29

30-day money-back guarantee. Instant download.

AI Disclosure: Drafted with Claude Code; all patterns from Next.js 15 and shadcn/ui as of April 2026.

Tools and references