- Published on
Chaining Regex Expressions in Zod: Is It Possible?
- Authors
- Name
- Ripal & Zalak
When working with Zod, a powerful schema validation library for TypeScript and JavaScript, you might encounter scenarios where you need to validate a field against multiple regex patterns. But is it possible to chain regex expressions in Zod, and if not, what are the alternatives? Let's dive into the topic with a clear example and practical solutions.
Chaining Regex in Zod: How to Handle Multiple Regex Validations in Zod
Suppose you have a schema for validating a user's full name. You want to:
- Ensure the name contains only alphabets.
- Require both a first name and a last name separated by a space.
- Set a minimum length of 2 characters.
Here’s a sample code snippet where multiple .regex()
calls are used:
import { z } from 'zod'
export const Schema = z.object({
fullname: z
.string()
.regex(new RegExp(/^[a-zA-Z]+[-'s]?[a-zA-Z ]+$/), 'Name should contain only alphabets')
.regex(new RegExp(/^[a-zA-Z]+\s+[a-zA-Z]+$/), 'Please enter both firstname and lastname')
.min(2, 'Name should have at least 2 alphabets'),
})
Issue: While this code runs, only the error message for the first regex is displayed, even if subsequent regex patterns fail. Zod does not natively support chaining regex validations with distinct error messages for each.
.refine()
Instead of .regex()
Solution: Using The .refine()
method in Zod allows you to define custom validation logic with specific error messages. Here's how you can rewrite the schema using .refine()
:
export const Schema = z.object({
fullname: z
.string()
.refine((value) => /^[a-zA-Z]+[-'s]?[a-zA-Z ]+$/.test(value), {
message: 'Name should contain only alphabets',
})
.refine((value) => /^[a-zA-Z]+\s+[a-zA-Z]+$/.test(value), {
message: 'Please enter both firstname and lastname',
})
.min(2, { message: 'Name should have at least 2 alphabets' }),
})
.refine()
?
Why - Allows chaining multiple validations with custom error messages.
- Each validation step can have its own logic and message.
- Offers better flexibility for complex validations.
Alternative: Custom Validation Functions
For even more control, you can write a single .refine()
with custom logic:
export const Schema = z.object({
fullname: z
.string()
.refine(
(value) => {
if (!/^[a-zA-Z]+[-'s]?[a-zA-Z ]+$/.test(value)) {
return false
}
if (!/^[a-zA-Z]+\s+[a-zA-Z]+$/.test(value)) {
return false
}
return true
},
{
message: 'Name must contain only alphabets and include both firstname and lastname',
}
)
.min(2, { message: 'Name should have at least 2 alphabets' }),
})
This method consolidates all checks into a single validation, reducing redundancy but requiring more manual error handling.
FAQs
.regex()
validations?
1. Why does Zod not allow multiple Zod's .regex()
is designed for simple, single-pattern validations. When chaining .regex()
, only the first failing pattern triggers an error, skipping subsequent checks.
2. Can I display multiple error messages for a single field?
Yes, but you need to use .refine()
for each validation step. Alternatively, you can use .superRefine()
to collect all errors and return them together.
.superRefine()
?
3. What is .superRefine()
allows you to define custom validation logic while collecting multiple errors for a single field. Here’s an example:
export const Schema = z.object({
fullname: z.string().superRefine((value, ctx) => {
if (!/^[a-zA-Z]+[-'s]?[a-zA-Z ]+$/.test(value)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Name should contain only alphabets',
})
}
if (!/^[a-zA-Z]+\s+[a-zA-Z]+$/.test(value)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Please enter both firstname and lastname',
})
}
}),
})