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
bash
bun run dev # Dev server
bun run build # Production build
bun run typecheck # Type check
npx shadcn add [component] # Add shadcn component
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"
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)"
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."
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'."
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."
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)"
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)"
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"
plaintext
Tailwind Patterns That Work Well
Be specific about layout
Vague styling prompts get inconsistent results:
Weak:
"Make the layout look nice"
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."
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"
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.
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 /
[→ 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.*
Top comments (0)