DEV Community

Sangmin Lee
Sangmin Lee

Posted on Originally published at claudeguide.io

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

Originally published at claudeguide.io/claude-code-nextjs-frontend

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
Enter fullscreen mode Exit fullscreen mode


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

Enter fullscreen mode Exit fullscreen mode


plaintext


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"
Enter fullscreen mode Exit fullscreen mode


plaintext

Strong prompt:

"Create app/dashboard/page.tsx — a server component that:
- Fetches user's last 30 days of API usage from the usageRecords table via Drizzle
- Shows a summary card row: total cost, total calls, top model (3 Cards)
- Shows a line chart of daily cost (Recharts LineChart, client component in separate file)
- Shows a data table of recent calls (shadcn/ui Table, last 20 rows)
- Uses Suspense boundaries with skeleton loading states
- Handles empty state (no data yet)"
Enter fullscreen mode Exit fullscreen mode


plaintext

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."
Enter fullscreen mode Exit fullscreen mode


plaintext

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'."
Enter fullscreen mode Exit fullscreen mode


plaintext


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."
Enter fullscreen mode Exit fullscreen mode


plaintext

Commonly used shadcn components with Claude Code

Forms with validation:

"Create a settings form at components/SettingsForm.tsx:
- shadcn Form + Input + Select + Button
- Zod schema: name (string, min 2), email (email), plan (enum: free, pro)
- React Hook Form with zodResolver
- onSubmit calls updateSettings() mutation
- Show toast on success/error (shadcn useToast)"
Enter fullscreen mode Exit fullscreen mode


plaintext

Data tables:

"Create a users data table with:
- shadcn Table, sorted by createdAt descending
- Columns: name, email, plan, joined date, actions (View, Delete)
- Row click navigates to /users/[id]
- Delete shows shadcn AlertDialog confirmation
- Pagination (25 rows per page)"
Enter fullscreen mode Exit fullscreen mode


plaintext

Modals/dialogs:

"Add an invite team member dialog to app/team/page.tsx:
- shadcn Dialog triggered by 'Invite Member' button
- Form: email input + role Select (Admin/Member)
- Submit calls inviteTeamMember() server action
- Close on success, show error inline on failure"
Enter fullscreen mode Exit fullscreen mode


plaintext


Tailwind Patterns That Work Well

Be specific about layout

Vague styling prompts get inconsistent results:

Weak:

"Make the layout look nice"
Enter fullscreen mode Exit fullscreen mode


plaintext

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."
Enter fullscreen mode Exit fullscreen mode


plaintext

Responsive design prompts

"Responsive card grid:
- Mobile: single column
- tablet (md): 2 columns  
- desktop (lg+): 3 columns
- Each card: white background, rounded-lg, border, shadow-sm, p-6
- Hover: shadow-md transition"
Enter fullscreen mode Exit fullscreen mode


markdown

Dark mode support

If your project uses dark mode, add to CLAUDE.md:

## 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.
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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."
Enter fullscreen mode Exit fullscreen mode

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."
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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."
Enter fullscreen mode Exit fullscreen mode

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 /

[→ Get Power Prompts 300 — $29](https://shoutfirst.gumroad.com/l/agfda?utm_source=claudeguide&utm_medium=article&utm_campaign=claude-code-nextjs-frontend)

*30-day money-back guarantee. Instant download.*
Enter fullscreen mode Exit fullscreen mode

Top comments (0)