DEV Community

Cover image for Form Validation with Zod and Prismane
Prismane
Prismane

Posted on

Form Validation with Zod and Prismane

05 - Form Validation with Zod

Introduction

Greetings, everyone! Welcome to our tutorial on form validation in Prismane using the Zod library.

Zod is a TypeScript-first schema declaration and validation library. It allows developers to define data structures (schemas) in a type-safe manner and provides validation functions to ensure that data adheres to the specified structure.

By using Zod in Prismane, developers can leverage their form validation even more by easily creating more complex validators.

All of the code in the example below can be directly accessed through the GitHub Repository.

Before continuing, you should get familiar with the Zod library, if you are not.

Initial Setup

From this point on, we will accept that you understand how Prismane’s useForm hooks works and you know how to build forms using Prismane. If not, please refer to this tutorial.

Install Zod

Firstly, we need to install the zod package from the npm registry. We can do this by running this command:

npm install zod
Enter fullscreen mode Exit fullscreen mode

Initial App

Now, we are going to use this initial app built only with Prismane:

import {
  Center,
  Card,
  Form,
  Button,
  TextField,
  PasswordField,
} from "@prismane/core";
import { useForm } from "@prismane/core/hooks";
import { z } from "zod";

function App() {
  const { handleSubmit, handleReset, register } = useForm({
    fields: {
      username: {
        value: "",
        validators: {
          required: (v) => p(v, z.string()),
          min: (v) => p(v, z.string().min(5)),
        },
      },
      password: {
        value: "",
        validators: {
          required: (v) => p(v, z.string()),
          min: (v) => p(v, z.string().min(5)),
        },
      },
    },
  });

  return (
    <Center w="100vw" h="100vh">
      <Card w={300} h={400}>
        <Form
          onSubmit={(e: any) => {
            handleSubmit(e, (v: any) => console.log(v));
          }}
          onReset={() => handleReset()}
        >
          <TextField
            placeholder="Enter username: "
            label="Username:"
            {...register("username")}
          />
          <PasswordField
            placeholder="Enter password: "
            label="Password:"
            {...register("password")}
          />
          <Button variant="primary" type="submit">
            Submit
          </Button>
        </Form>
      </Card>
    </Center>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

💡 This application creates a form using the useForm hook, creates a form and registers two fields - username and password.

Adapt Zod to Prismane Validators

Great! Now, let's solve a key problem. Zod's validators don't work seamlessly with Prismane by default. To fix this, we'll create a function that adapts Zod validators to fit Prismane's form validation style. This way, you can smoothly use Zod with Prismane for your forms.

Firstly, let’s create the zodToPrismane file, where we will create our transform function.

touch zodToPrismane.ts
Enter fullscreen mode Exit fullscreen mode

Then, inside the zodToPrismane.ts file, we are going to add the following function:

const p = (value: any, validator: any) => {
  const result = validator.safeParse(value);

  if (!result.success) {
    return result.error.errors[0].message;
  }

  return null;
};

export default p;
Enter fullscreen mode Exit fullscreen mode

We are going to name it p so it can be shorter and not visually blocking when we use it.

The p function executes Zod's validator and provides the error message if there's one, or null if there are no errors. This way we can adapt the Zod validator to the structure of a Prismane validator.

Add Validators

Add Validators

Now, after having the p function, we can easily add Zod validators to Prismane’s useForm hook:

...
import p from "./zodToPrismane";
...

...
const { handleSubmit, handleReset, register } = useForm({
  fields: {
    username: {
      value: "",
      validators: {
        required: (v) => p(v, z.string().min(1)),
        min: (v) => p(v, z.string().min(5)),
      },
    },
    password: {
      value: "",
      validators: {
        required: (v) => p(v, z.string().min(1)),
        min: (v) => p(v, z.string().min(5)),
      },
    },
  },
});
...
Enter fullscreen mode Exit fullscreen mode

💡 We are adding two validators to each of our fields - required and min.

The required validator isn’t directly supported by Zod, so we will have to check if the length of the value is at least 1 using the .min() property of the z.string() validator.

The min validator can be created by using the .min() property of the z.string() validator.

Let’s see the current result:

Image description

Customizing the Error Messages

With Zod, we can modify the default error messages to create more personalized errors for our fields.

For the required validator we can pass an object to the z.string().min() and give a value to the message property.

username: {
 ...
  validators: {
    required: (v) => p(v, z.string.min(1, {
      message: "The username field is required!",
    })),
        ...
  },
},
password: {
  ...
  validators: {
    required: (v) => p(v, z.string.min(1, {
      message: "The password field is required!",
    })),
    ...
  },
},
Enter fullscreen mode Exit fullscreen mode

For the min validator we can pass an object as a second parameter to the .min() and give a value to the message property.

username: {
  ...
  validators: {
    ...
    min: (v) =>
      p(
        v,
        z.string().min(5, {
          message: "Username must be longer than 5 characters!",
        })
      ),
  },
},
password: {
  ...
  validators: {
    ...
    min: (v) =>
      p(
        v,
        z.string().min(5, {
          message: "The password must be longer than 5 characters!",
        })
      ),
  },
},
Enter fullscreen mode Exit fullscreen mode

Great! Now all of the error messages are changed and personalized for the fields that we have and use.

Now, let’s see the final result:

Image description

Great, now you can build even form validators with ease using Prismane and Zod!

Feel free to connect with us on Twitter, GitHub, Reddit

You can support us through Contributing and OpenCollective.

Check out our website for more in detail information.

Top comments (0)