Next.js 32: Forms With Server Actions
easy⏱ 5 mincoursenextjs
action={fn} instead of onSubmit
In a real Next.js app you skip onSubmit, event.preventDefault(), and manual fetch entirely: <form action={addComment}> tells React to call addComment(formData) on submit, where formData is a native FormData built from every named input in the form. No controlled inputs required — read values with formData.get('fieldName').
// app/actions.ts
'use server';
export async function addComment(formData: FormData) {
const text = formData.get('comment');
await db.comment.create({ data: { text } });
}
// app/posts/[id]/page.tsx
import { addComment } from '../../actions';
export default function PostPage() {
return (
<form action={addComment}>
<input name="comment" placeholder="Write a comment…" />
<button type="submit">Post</button>
</form>
);
}
Progressive enhancement
Because action on a <form> is a real HTML attribute Next.js wires up, the form works before JavaScript loads — a slow connection or a JS error doesn't break submission, it just falls back to a full-page navigation. Once React hydrates, the same submission happens without a reload. You get resilience for free.
This sandbox is React 18
<form action={fn}> with a function needs React 19's react-dom; this sandbox only ships React 18's UMD build. So in the exercise we mimic the exact same data shape — a function called with a FormData — using a normal onSubmit handler that builds the FormData itself.
Wire an action-shaped function
Write commentAction(formData) — a function that takes a FormData, not individual arguments — and reads the comment with formData.get('comment'). In your submit handler, build new FormData(event.target) and pass it straight to commentAction. Keep export default App.