All React templates

Next.js + Server Actions + Shadcn UI

Forms with Server Actions, Zod validation, and Shadcn UI primitives.

DevZone Tools2,940 copiesUpdated Mar 18, 2026Next.jsReactTypeScriptShadcn Ui
# CLAUDE.md — Next.js + Server Actions + Shadcn UI

## Forms & mutations

- Use Server Actions for every form. The client form component imports the action and passes it to `<form action={...}>`.
- Validate input inside the action with Zod. Reject invalid input before touching the database.
- Return a discriminated `{ ok: true, data } | { ok: false, error }` from every action. The client renders state from this — never throws.
- Use the `useActionState` (or `useFormState`) hook to keep server-returned errors next to the form fields.
- For optimistic UI, use `useOptimistic` — don't manually duplicate state.

## Shadcn UI

- Components live in `components/ui/`. Generated with `npx shadcn add <component>` — keep them under your control.
- Compose from primitives: never reach for a "kitchen sink" library on top of Shadcn.
- For variants, extend the existing `cva` class string — don't fork the file.
- Re-export Shadcn primitives from a single barrel only if you also wrap them. Otherwise import directly from `components/ui/<file>`.
- Shadcn components are client components by default. If a primitive is purely presentational, copy it into a server component file and drop the `'use client'` directive.

## Validation

- One Zod schema per form, exported from `lib/validators/<feature>.ts`.
- Infer types: `type FormInput = z.infer<typeof formSchema>`. Never declare the type by hand.
- Reuse the schema on the client (resolver for `react-hook-form`) and the server (action input check). Don't duplicate.

## Patterns

- Loading states: use the `pending` flag from `useActionState` — don't track it with `useState`.
- After a successful mutation, call `revalidatePath` or `revalidateTag` from the action — not `router.refresh()` from the client.
- Handle redirects with `redirect()` *inside* the action. The client never decides where to go after a mutation.

## Don't

- Don't wrap a Server Action in a fetch from a client. Pass it to `<form action>` or call it directly via `useTransition`.
- Don't return raw `Error` objects — they don't serialize. Return shape-checked plain objects.
- Don't put business logic in form components. Keep the form thin; logic lives in the action.
- Don't mix Shadcn with another UI kit. Pick one design system and commit.

Other React templates