clipboard-listEngineering
Forms & Validation
Controlled vs uncontrolled inputs, React Hook Form, Zod schema validation, server actions, and error UX.
1 item
Links1
01NotesNote
Controlled vs uncontrolled
- Controlled: React state is the single source of truth (
value+onChange). Predictable, easy to react to every keystroke — but re-renders on every change. - Uncontrolled: the DOM holds the value; you read it on submit via a ref. Less re-rendering, less code for simple forms. React Hook Form leans on this, which is why it's fast.
For anything beyond a trivial form, reach for React Hook Form — it minimizes re-renders, handles touched/dirty/error state, and integrates cleanly with schema validation.
Validate with a schema, share it everywhere
- Define the shape once with Zod, then:
- infer the TypeScript type from it (
z.infer) — no duplicate type definitions, - validate on the client for instant feedback (via the RHF resolver),
- validate the same schema on the server (API route / server action).
- One schema = one source of truth for types and rules. This is the single biggest win in form code.
Client validation is UX; server validation is security
- Client-side validation is for fast, friendly feedback. It can always be bypassed.
- Always re-validate on the server. The server is the only trust boundary. A server action or API handler must validate its input regardless of what the client did.
Server Actions for mutations
- In Next.js, a
"use server"action can receive the form data, validate with Zod, perform the mutation, and revalidate the cache — no separate API route. Return field-level errors to drive the UI. useFormStatus/useActionStategive pending and error state for a clean submit experience.
Error & submission UX
- Show errors inline, next to the field, on blur or submit — not a wall of errors at the top.
- Disable the submit button while pending and show a spinner; prevent double-submits.
- Preserve user input on a failed submit — never make them retype everything.
- Associate errors with inputs via
aria-describedbyand mark invalid fieldsaria-invalid(ties into the accessibility note).