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
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;
💡 This application creates a form using the
useForm
hook, creates a form and registers two fields -username
andpassword
.
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
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;
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, ornull
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)),
},
},
},
});
...
💡 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 thez.string()
validator.The
min
validator can be created by using the.min()
property of thez.string()
validator.
Let’s see the current result:
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!",
})),
...
},
},
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!",
})
),
},
},
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:
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)