Form Handling & Validation in Next.js

5 questions found

How do you submit a form directly to a server action in Next.js without writing any client side JavaScript?

Beginner
You pass your server action function directly to the form element's action attribute, and Next.js automatically handles collecting the form data and sending it to your server action, even working correctly before any client side JavaScript has loaded, thanks to progressive enhancement.
// app/contact/page.js
import { submitContact } from './actions';

export default function ContactPage() {
  return (
    <form action={submitContact}>
      <input name="email" type="email" required />
      <button type="submit">Send</button>
    </form>
  );
}
Real-world example A simple contact form submits directly to a server action, working correctly even for users on slow connections where the page's JavaScript has not fully loaded yet.

Common follow-ups: What does progressive enhancement mean in the context of forms?;How do you read the submitted values inside the server action?

Server Actions & Mutations;Route Handlers (API Route.js)

How do you validate form data on the server before saving it, and show validation errors back to the user?

Intermediate
Inside your server action, you check the submitted values against your validation rules, often using a library like zod, and if validation fails, you return an object describing the errors instead of throwing, which you can then read on the client using the useActionState hook to display messages next to the relevant fields.
'use server';
import { z } from 'zod';

const schema = z.object({ email: z.string().email() });

export async function submitContact(prevState, formData) {
  const result = schema.safeParse({ email: formData.get('email') });
  if (!result.success) {
    return { error: 'Please enter a valid email address' };
  }
  await saveContact(result.data);
  return { success: true };
}
Real-world example A newsletter signup form shows a clear error message right under the email field if a visitor types an invalid email address, thanks to validation happening safely inside the server action.

Common follow-ups: What is the useActionState hook and how does it connect to a server action?;Should validation also happen on the client for a faster response?

Server Actions & Mutations;Client Components & Hydration

How do you show a pending or loading state while a form is being submitted using a server action?

Intermediate
You use the useFormStatus hook inside a child component of the form, which tells you whether the form is currently submitting, letting you disable the submit button or show a loading spinner while the server action is running, improving the experience for users on slower connections.
'use client';
import { useFormStatus } from 'react-dom';

function SubmitButton() {
  const { pending } = useFormStatus();
  return <button disabled={pending}>{pending ? 'Sending...' : 'Send'}</button>;
}
Real-world example A checkout form disables its submit button and shows a spinner the moment a customer clicks pay, preventing them from accidentally submitting their order twice while it processes.

Common follow-ups: Why does useFormStatus need to be used in a child component rather than the form component itself?;What other information does useFormStatus provide besides pending?

Server Actions & Mutations;Loading UI & Streaming with Suspense

How would you handle file uploads through a form using a server action in Next.js?

Advanced
You read the uploaded file directly from the FormData object inside your server action using its field name, which gives you a File object that you can then process, save to disk, or upload to a cloud storage service, all without needing a separate API route.
'use server';

export async function uploadAvatar(formData) {
  const file = formData.get('avatar');
  if (file && file.size > 0) {
    const buffer = await file.arrayBuffer();
    await saveToStorage(buffer, file.name);
  }
}
Real-world example A user profile page lets someone upload a new avatar image directly through a server action, which reads the uploaded file and saves it to cloud storage without needing a separate API endpoint.

Common follow-ups: What is the maximum file size a server action can handle by default?;How do you validate the file type before accepting an upload?

Server Actions & Mutations;Security Best Practices in Next.js

What is optimistic UI, and how can you apply it to a form submission for a better user experience?

Advanced
Optimistic UI means immediately updating the interface as if the action already succeeded, before the server actually confirms it, using the useOptimistic hook to show the expected result right away, and then reconciling with the real server response once it arrives, which makes the app feel instant.
'use client';
import { useOptimistic } from 'react';

function CommentList({ comments, addComment }) {
  const [optimisticComments, addOptimistic] = useOptimistic(comments, (state, newComment) => [...state, newComment]);
  return null; // simplified for brevity
}
Real-world example A comment section shows a new comment immediately after a user submits it, before the server has even finished saving it, making the app feel fast and responsive even on a slower network.

Common follow-ups: What happens if the server action fails after an optimistic update was already shown?;How does useOptimistic differ from simply updating regular state?

Server Actions & Mutations;State Management in Next.js Apps