Validate Form Data Through a Remix Action using Zod

Ian Jones
InstructorIan Jones
Share this video with your friends

Social Share Links

Send Tweet

At this point, your form will accept any type of input that users desire. This isn't good, you need to add form validation.

Form validation is another area that there are many ways to accomplish what you need. One great way to get easy form validation is through a library called Zod. Zod allows you to create a schema to parse your form input against. It will return form and field errors when input doesn’t match the rules that you supply.

With Zod in place, you’ll check form input in the action previously defined. If an error is found, you’ll return an object passing in the errors you find as well as the input that users submitted. This will be used to render error messages in the form and reset form state to what was submitted. This is easy to accomplish with Remix json helper that will also set the error message for you.

Along the way you will also see how easy it is to type this data.

Ian Jones: [0:00] Right now, if you press the submit button without filling out the inputs, an empty post will be created. You want the user to at least fill out the body of a post. To accomplish this, you will need to add data validation in your action.

[0:18] As we all know, when you encounter a problem, the first thing you should do is install an npm package. Head over to the terminal and run npm install zod. Zod is a validation library where you can define a schema for your input and validate that input against the rules you've written. Zod works great with TypeScript, and has many useful helper functions.

[0:48] Head over to your Services folder and create a validations.ts file. In the validations file, import Z from Zod. It's time to create the createPost schema. CreatePost will be an object. This object will have a key of title, and the title will be optional.

[1:22] Next, as you might have guessed, the object will have a body of type string, where the minimum length is greater than or equal to 1.

[1:36] Back in your index route, you can call const result = createPost.safeParse. Now, you can pass in raw title and raw body. If you use the parse function, Zod will throw an error, if the input doesn't match the schema. You want to be able to handle the error yourself.

[2:03] SafeParse will return an object with the attribute success error and data to result that success is false, then there was an error in parsing the data. Here, you can return an object with the key of error, then parse result.error.flattened.

[2:23] You also want to add the form fields to return state of the form to the user. To show you what the Response will look like, head up above the Action function and create an Action data type. The error will have a form error attribute which will be an array of strings.

[3:02] Then there will be a field errors attribute, which is an object with a key of title. Title will be an array of strings and then a key of body. Which will also be an array of strings. Next, we have fields, which are title and body.

[3:22] All of the attributes with the question mark are optional. Instead of using raw title, you can use result.data.title. Likewise with raw body, you're not using the reference to the post, so you can just remove it.

[3:46] One last thing before you move on, wrap this object with a call to the JSON helper function from Remix. In the second param, add a status of 400. Open up your dev console in the browser and you can see this validation code in action.

[4:10] When you click Create Post with an empty body, you can see Remix is returning an error with a status of 400. You are returning JSON back from the Action. To get a reference to the Action Response, call useActionData passing in the action data type.

[4:33] Now, you can pass error and fields down into the post form component. The first thing you should do, is add error and fields to the post form type. At this point, the type can live in its own file. Create a type of props and paste in the action data type.

[5:05] Props will be a union type of the action data type and the component props without ref type. Back in the component file, import type Props from types. There, you can pull off error and fields from the props. Next, if there is a field error, you should display under the input in red.

[5:42] Check if the fielderror.title exists. If it does, render a P tag with red text. Now, you can do the same for the body field error and the top-level form error. Head over to your browser and let's see this working.

[6:10] When you create a post with an empty form, you get the error displayed with "String must contain at least one character." To prove things are still working, add a post without a title. Notice what happens when you type into the title field and hit "Submit".

[6:34] The form values disappear. The action is already passing back the form fields it received. All you need to do, is add the form fields to the default value of your input and text area. Let's try it again. When you type into the title field and hit submit, the form keeps its state, but the extra error information is displayed.

[7:02] It looks like TypeScript is upset. You have to make the error and fields coming from Action data undefined because these values aren't set until the user submits the form. Let's review what you've learned. You installed Zod and created a Create Post Schema to parse the data coming into the Action's function.

[7:34] If somebody sends a request that didn't successfully parse, you returned the error in the form fields. Lastly, you added the errors to the post form and passed any values the user typed in back to the form.