How to Use Zod Transform for Custom Form Validation and Manipulation

When working with form inputs, it’s often important to validate or manipulate user entries before using the data. Zod is a highly flexible tool that has an abundance of provided checks. You can use it to validate the types of data, restrict length, make items optional or required, and so on. It also allows developers to expand and customize validation to their needs. One strategy for this is using the Zod transform method to manipulate and validate an entry. You can customize the error message returned as well.

Construct validation and transformation logic.

For example, say you have a freeform text entry field where you expect users to enter a link. Of course, you can do some UI validation, but you should always work off of the assumption that the data needs to be validated server side too. So, we are expecting that any length or format of text could have come through on this field.

To start, we define a couple of regex expressions to check for an http/https prefix and to check for standard URL format:


const httpRegex = /^(http|https):/
// from https://uibakery.io/regex-library/url
const completeUrlRegex = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)$/

We can then incorporate these checks into a Zod schema to both check for valid URLs and transform them to match the expected format:

const validateUrls = z
  .string()
  .max(1000)
  .transform((val, ctx) => {
    let completeUrl = val;
    if (!httpRegex.test(completeUrl)) {
      completeUrl = `https://${completeUrl}`;
    }
    if (!completeUrlRegex.test(completeUrl)) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: "Invalid Link",
      });

      return z.NEVER;
    }
    return completeUrl;
  });

Here, we use Zod to do some basic checks — like making sure the value is a string and putting some arbitrary upper limit on its length. Transform is where you can really lean into Zod’s flexibility. The first part of this example touches on the transformation aspect. We check against the httpRegex, and if someone has entered a URL without a protocol (e.g. google.com), it will be transformed to include one (https://google.com).

The second part of the example confirms whether the user has entered a legitimate URL at all. This is where Zod transform’s validation features come in handy. We check the URL format, now including a protocol. ctx.addIssue allows us to add a custom error message to the Zod validation to display to users in the case of this failure. This custom validation message doesn’t override any other messages provided by Zod, such as a “required” message.

Validation errors on URL form entries
URL Validation with Zod Transform

Validate with ZFD.

Now it’s easy to tack on our custom validation and transformation to a FormData validator using zod-form-data:


const formSchema = zfd.formData({
  link: zfd.text(validateUrls)
});

formSchema.safeParse(formData);

Zod Transform

When the base Zod validators aren’t quite getting the nuances of form validation you need, Zod transform fills the gap with flexibility and customization. Its ability to both manipulate and validate data allows for coverage of weird edge cases, all while providing informative responses back to the user.

Conversation
  • José Fournier says:

    Thank you for this post it is of great interest.
    Nevertheless, I am new to both nuxtui and zod and it would help me to have a more comprehensive example presenting how this (which logic I understand) articulates with the form template and its script.
    For example, it would be kind of you to show me how the zod example presented in the nuxtui documentation (https://ui.nuxt.com/forms/form#zod) can be changed to make use of your link example.

  • Join the conversation

    Your email address will not be published. Required fields are marked *