In this tutorial, we'll learn how to use the Zod and Action function to validate form data in Remix.
Zod is a schema validation library for TypeScript. It allows us to define a schema for our data and validate it against the schema.
When you make a POST request to your route, you can use the Action function to validate the data before it's processed.
Let's add a new route to our app called /signup and handle the form submission.
Add the following code to app/routes/signup.tsx:
import type { ActionArgs } from "@remix-run/node";
import { Form, useActionData } from "@remix-run/react";
import { redirect, json } from "@remix-run/node";
import { z } from "zod";
export async function action({ request }: ActionArgs) {
  // Get the form data from the request
  const formData = Object.fromEntries(await request.formData());
  // Define the schema for the form data
  const schema = z.object({
    name: z.string().min(1),
    email: z.string().email(),
    password: z.string().min(8),
  });
  // Validate the form data against the schema
  const parsed = schema.safeParse(formData);
  // If the validation fails, return the errors to the client
  if (!parsed.success) {
    return json({ error: parsed.error.format() });
  }
  // If the validation succeeds, get the data from the parsed object
  const newUser = parsed.data;
  console.log(newUser);
  // Use the `newUser` object to create a new user in your database
  return redirect("/signup");
}
export default function User() {
  // Get the form validation errors returned from the server
  const data = useActionData<typeof action>();
  return (
    <>
      <h1>Create a new user</h1>
      <Form method="post">
        <input type="text" name="name" placeholder="Name" />
        {data && data.error.name && <p>{data.error.name._errors[0]}</p>}
        <input type="email" name="email" placeholder="Email" />
        {data && data.error.email && <p>{data.error.email._errors[0]}</p>}
        <input type="password" name="password" placeholder="Password" />
        {data && data.error.password && <p>{data.error.password._errors[0]}</p>}
        <button type="submit">Create User</button>
      </Form>
    </>
  );
}
You can use useActionData to get the data returned from the server. In this case, we're getting the form validation errors.
const data = useActionData<typeof action>();
We can then use the data.error object to display the validation errors on the client.
Here is the output when the form is submitted with invalid data:
{
  _errors: [],
  name: { _errors: [ 'String must contain at least 1 character(s)' ] },
  email: { _errors: [ 'Invalid email' ] },
  password: { _errors: [ 'String must contain at least 8 character(s)' ] }
}
That's it! You can now validate form data in Remix using Zod and Action function.
More Articles
- Use Remix Action to handle form submission
 - Use Remix Loader to fetch data from an external API
 - Validating form data in Remix using Zod and Action function
 - Add a search form in Remix with data fetching
 - Show a flash message in Remix after form submission
 - Discover the best SaaS Starter Kits based on Remix