Client-Side Form Validation
Adding the remaining first and last name fields to the form is a similar process to adding the email field. Copying and pasting the email field and modifying the name and description will do the trick:
// inside RegistrationForm.tsx
return (
<Form {...form}>
<form
className="space-y-8"
>
<FormField
control={form.control}
name="first"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>First Name</FormLabel>
<FormControl>
<Input placeholder="" {...field} />
</FormControl>
<FormDescription>Your first name.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="last"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Last Name</FormLabel>
<FormControl>
<Input placeholder="" {...field} />
</FormControl>
<FormDescription>Your last name.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
...
At this point the form fields will be displayed one below the other.
In order to display the first and last name fields side by side, we can wrap them in a div that uses Tailwind's Flexbox classes to put them side by side with a gap in between:
<form className="space-y-8">
<div className="flex gap-2">
{/* FormFields for first and last name */}
</div>
{/* FormField for email */}
Now the form fields for the first and last name will be displayed side by side above the email field:
However, when the submit button is clicked, nothing happens. This is because the handleSubmit
function isn't connected to the actual onSubmit
event that gets triggered when the submit button is clicked.
Writing the onSubmit
Function
Inside of RegistrationForm.tsx
, above the return
, create a new async onSubmit
function. The function's data will be given the type of our schema, thanks to the z.infer
trick. This ensures we don't have to perform any manual synchronization since any alterations in the schema will correspondingly modify the rest. For the time being, the function will console log the data that comes in:
const onSubmit = async (data: z.infer<typeof schema>) => {
console.log(data);
}
Now it's time to establish a connection with the form.
Connecting the onSubmit
Function to the Form
Inside of the <form>
being returned from the component, add an onSubmit
prop that will be given the form.handleSubmit(onSubmit)
function. This will ensure that all validations are applied:
// inside of the `return` statement
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
...
With the onSubmit
connected, let's give the form a test run.
Testing the Form
First we'll keep all of the fields empty and hit the submit button. As expected, everything turns out to be invalid, and checking the console reveals that no output has been generated.
Next, fill out the form with some random data and hit submit again. This time around, we can see in the console that onSubmit
has been invoked with the data, and everything has been trimmed and validated. This is a clear indication that our client-side validation is working perfectly.
And there you have it, folks! Client-side validation can be that simple.
In the next step, we'll look at how you can post this to the server and validate it there.