# Frontend Next Forms

> React Hook Form + Zod forms in Next.js: checkout validation, phone input, conditional refinements, responsive notifications. Use when building forms, validation schemas, or form UI in Next.js storefronts.

- Skill: `xmuhameed/frontend-next-forms` (Agent Skill)
- Install (CLI): `npx skillmds@latest add xmuhameed/frontend-next-forms`
- Raw SKILL.md: https://api.skillmd.com/api/skills/xmuhameed/frontend-next-forms/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: xmuhameed (https://skillmd.com/u/xmuhameed)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/xmuhameed/frontend-next-forms

---


# Forms

## Checkout (complex — canonical)

```typescript
// features/checkout/hooks/useCheckoutForm.ts
const form = useForm<CheckoutFormData>({
  resolver: zodResolver(checkoutFormSchema),
  mode: 'onBlur',
  defaultValues: { ... },
});
```

Schema in `utils/validation.ts` with `.refine()` for conditional rules (recipient mode, address type).

## Auth Forms (simple)

`AuthForm.tsx` uses controlled `useState` — not RHF. Acceptable for simple login.

## Phone Validation

```typescript
// utils/phone-validation.ts + libphonenumber-js
validatePhone(value, countryCode)
```

Component: `components/ui/phone-input-shadcn.tsx`

## shadcn Form

```tsx
<Form {...form}>
  <FormField control={form.control} name="email" render={({ field }) => (
    <FormItem>
      <FormLabel>Email</FormLabel>
      <FormControl><Input {...field} /></FormControl>
      <FormMessage />
    </FormItem>
  )} />
</Form>
```

## Conditional Zod

```typescript
.refine(data => data.isRecipient || data.senderName, {
  message: 'Sender name required',
  path: ['senderName'],
})
```

## Notifications

`useNotification().notify()` — toast on desktop, drawer on mobile.
`providers/NotificationProvider.tsx`

## File Inputs in Forms

Not in RHF — separate `useState<File | null>` with preview. Pass File to service on submit.

## Prefill from Auth

```typescript
useEffect(() => {
  if (user) form.reset({ email: user.email, phone: user.phone, ... });
}, [user]);
```

