Mastering forms in Next.js 15 and React 19

Kolby Sisk
Udacity Eng & Data
Published in
5 min readJan 10, 2025

Creating forms in modern React has evolved significantly with the latest releases. In this post we’ll explore best practices for building modern forms with the newest primitives and APIs.

First, it’s important that you understand best practices for creating forms in the previous generation of React. Much of the same rules apply today such as using the native features when possible and not reaching for controlled components by default.

🚧 Checkout the code for the completed examples. This post will include snippets, but the repo contains the full runnable examples.

Here’s what we’ll be exploring

  • Server Actions: asynchronous functions that are executed on the server.
  • useActionState: a Hook that allows you to update state based on the result of a form action.
  • useOptimistic: optimistically update your UI after submitting a form.
  • revalidateTag: purge cached data after a mutation.
  • Form: a Next.js component that provides prefetching, client-side navigation on submission, and progressive enhancement.

Server Actions

A Server Action is an asynchronous function that runs on a server. They can be called in Server and Client Components to handle form submissions and data mutations.

Here’s a basic example of a Server Action.

And this is how we would use that Server Action.

Our submitComment Server Action can be imported directly into our Client Component and passed as the action for the form element. When the form is submitted it calls the function and provides the formData as a param. This Server Action is performing a mutation by creating a record in a database. After a mutation you’ll typically need to purge the cache of previously cached requests, which we can do by calling revalidateTag.

useActionState

Now let’s expand on this and build a more complex form. This form will include data validation, error states, and pending states. We can facilitate all of these with React’s useActionState hook.

Notice that instead of providing the Server Action to form element, we provide it to the useActionState hook. It also accepts initial values, which this form doesn’t include, so we pass null.

The state value returned from the hook is the data that is returned from our Server Action, and the hook provides a pending state which we can use to disable our button while the Server Action is executing.

In this example the Server Action includes validation via Zod. If the data provided doesn’t pass Zod’s validation it’ll provide errors which we can return to client. These become available via the state value, and we can render an error message by accessing that state: {state?.errors?.name && <p aria-live=”polite”>{state.errors.name}</p>}

You’ll also notice that we return the values provided to the Server Action. By default, our form is reset after submitting it. To prevent this, we add a defaultState to our inputs, and set it to the values returned from the Server Action defaultValue={state?.values?.name ?? ‘’}.

useOptimistic

Optimistic Updates is a technique used to improve the user experience by immediately showing UI updates to the user, rather than waiting for the Server State to be updated and cache revalidated. React now provides a hook to make Optimistic Updates much easier.

We start by providing the hook with the current state. In this case, a list of comments. The hook provides a way to get the optimistic value, and a way to update it. We use optimisticComments to render our list of comments. After submitting the form we call addOptimisticComment and provide it with our new comment. Immediately, the UI is updated to show the new comment in the list. Meanwhile, we’ve called our Server Action to update the Server State and revlidate the cache. If an error was to occur while running our Server Action, the UI would fallback and undo the optimistic update.

Form

The Form component provide by Next.js is a handy way to prefetch data, update Search Params in the URL, or provide progress enhancements. In this example, we’ll use it to facilitate searching through a list of comments by updating a Search Param in the URL.

First, in our Server Component, we use a Search Param named query when fetching our comments.

In our UI component we use Next.js’ Form component and provide it the path that we want to prefetch. In this example we are on the search route already so it will refetch the data for the page. The name provided to the input will become the name of the Search Param that is updated, and the value of the input will be the Search Param value. When the form is submitted it will use the Search Param when fetching the comments to return results that match our query.

Conclusion

Building forms in Next.js and React has evolved significantly with the introduction of Server Actions, the useActionState and useOptimistic hooks, and Next.js’ dedicated Form component. These features enable more efficient data handling, streamlined validation, and seamless user experiences. By leveraging these APIs, you can craft forms that are both robust and user-friendly—without adding unnecessary complexity to your codebase.

Udacity is currently looking for skilled React developers to help us build talent transformation tools. If you’re skilled in developing international UIs at scale then reach out to me on Twitter @kolbysisk.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in Udacity Eng & Data

from the engineers and data scientists building Udacity

Written by Kolby Sisk

Builder of software with a passion for learning. I specialize in web development and user experience design. www.kolbysisk.com

Responses (6)

Write a response