zod-messages
v3.0.0
Published
Zod error result messages to validation readable object
Maintainers
Readme
Zod Messages
Zod Messages is a TypeScript project that provides a set of utilities for handling validation messages using the Zod library. This library allows you to easily validate your data and display error messages in a readable form within your components.
Features
- Easy Integration: Seamlessly integrates with the Zod validation library (Zod v4).
- Readable Messages: Transforms Zod error results into user-friendly validation messages.
- TypeScript Support: Fully typed and compatible with TypeScript.
- Framework-agnostic: The core (
zod-messages) has no React dependency. The React hook lives in thezod-messages/reactentry — React is an optional peer dependency, only needed if you use the hook.
Installation
Use your package manager of choice to install Zod Messages.
npm install zod-messagesReact is only required when you use zod-messages/react:
npm install react # >=18Usage with hooks (React)
import { useValidator } from 'zod-messages/react';
// your code hereSimple Example useValidator
// model.ts
export interface User {
name: string;
email: string;
age: number;
address : {
street: string;
city: string;
}
}// schema.ts
import { z } from 'zod';
export const AddressValidationSchema = z.object({
street: z.string().min(3),
city: z.string().min(3),
});
export const UserValidationSchema = z.object({
name: z.string().min(3),
email: z.email({ error: 'Invalid email address' }),
age: z.number().min(15, { error: 'Age must be at least 15' }),
address: AddressValidationSchema,
});// index.tsx
import { useValidator } from 'zod-messages/react';
import { ErrorMessage } from '@your-components/errorMessage/index';
export const YourComponent = () => {
const { validate, validationMessages } = useValidator<User>(UserValidationSchema);
const handleSubmit = (data: User) => {
const result = validate(data);
if (!result.isInvalid) {
// do something
}
}
return (
<form onSubmit={handleSubmit}>
<input type="text" name="name" />
<ErrorMessage message={validationMessages.name} />
<input type="text" name="email" />
<ErrorMessage message={validationMessages.email} />
<input type="number" name="age" />
<ErrorMessage message={validationMessages.age} /> //Age must be at least 15
<input type="text" name="address.street" />
<ErrorMessage message={validationMessages.address?.street} />
<input type="text" name="address.city" />
<ErrorMessage message={validationMessages.address?.city} />
<button type="submit">Submit</button>
</form>
);
}Validate a single field — including nested paths
validItem validates one field on change/blur without running the whole form. It accepts a top-level key or a path array (numeric segments walk array items):
const { validItem, validationMessages } = useValidator<User>(UserValidationSchema);
validItem('name', 'John'); // top-level key
validItem(['address', 'street'], 'Main St'); // nested object field
validItem(['children', 0, 'name'], 'Ann'); // array item field
// messages land at the same path:
// validationMessages.address?.streetAn unknown path throws an error describing the path, so typos surface immediately.
Usage without React (framework-agnostic)
//validation.ts
import { formatErrorMessages, ValidationResult } from 'zod-messages';
export const isUserValid = <T extends User>(data?: T): ValidationResult<T> => {
const result = UserValidationSchema.safeParse(data ?? initUserData);
return {
isInvalid: !result.success,
validationMessages: result.success ? {} : formatErrorMessages<T>(result.error),
}
};
//result
// {
// isInvalid: true,
// validationMessages: {
// name: 'Name is required',
// email: 'Invalid email address',
// age: 'Age must be at least 15',
// address: {
// street: 'Street is required',
// city: undefined
// }
// }
// }
Advanced example - use custom error messages
import { z } from 'zod';
export const UserValidationSchema = z.object({
name: z.string().min(3),
email: z.email({ error: 'Invalid email address' }),
address: AddressValidationSchema,
})
.superRefine((data, ctx) => {
if (data.address.city === 'New York') {
return ctx.addIssue({
code: 'custom',
path: ['address', 'city'],
message: 'City cannot be New York',
});
}
})or for use global error message
import { z } from 'zod';
import { eGlobalErrorMessage } from 'zod-messages';
export const UserValidationSchema = z.object({
name: z.string().min(3),
email: z.email({ error: 'Invalid email address' }),
})
.superRefine((data, ctx) => {
const diacritics = /[\u0300-\u036f]/g;
if (diacritics.test(data.name)) {
return ctx.addIssue({
code: 'custom',
path: [eGlobalErrorMessage.globalErrorMessage],
message: 'Name cannot contain diacritics',
});
}
})// index.tsx
//...
return (
<form onSubmit={handleSubmit}>
<input type="text" name="name" />
<ErrorMessage message={validationMessages.name ?? validationMessages.globalErrorMessage} />
</form>);
//...Migration from 2.x to 3.0
Zod v4 is required (
zod@^4). See the Zod v4 changelog — most notably{ message }params are deprecated in favor of{ error }.useValidatormoved from the root entry tozod-messages/react:- import { useValidator } from 'zod-messages'; + import { useValidator } from 'zod-messages/react';Everything else (
formatErrorMessages,hasAnyValidationErrorMessage,eGlobalErrorMessage,initialValidationResult, all types) stays importable fromzod-messages.New in 3.0: schemas chained with
.refine()/.superRefine()now work directly throughuseValidator— in Zod v4 they keep theZodObjecttype.
Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate.
License
This project is licensed under the ISC License - see the LICENSE file for details.
