Form validation TypeScript helper for React
v1.0.0Added in 1.0.0
Zod validation rules for React forms with one message set (English or Romanian), react-hook-form glue and a pretend request.
Fill the sign-up form and leave a field: its error appears under it and clears as you fix it. Submit with empty fields and every error shows at once, focus jumps to the first one. Switch the messages to the ready Romanian set, raise the password length or the minimum strength and try again. A valid form sends a pretend request and shows the result.
Form validation is a Pro React helper in the React hooks and utilities category, written in TypeScript for React 19. It installs as source with npx wingo-ui@latest add form-validation, together with Invoicing and the npm packages react-hook-form, @hookform/resolvers, zod and libphonenumber-js.
Add to a project
Requirements: React 19, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add form-validationForm validation is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import createValidators from @/lib/form-validation.
import { z } from "zod"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { createValidators, fieldError, useZodForm } from "@/lib/form-validation"
// English messages by default; pass VALIDATION_MESSAGES_RO for the Romanian set
const v = createValidators()
const schema = z.object({ email: v.email(), cui: v.cui({ required: false }) })
export function CompanyForm({ onSave }: { onSave: (values: z.output<typeof schema>) => Promise<void> }) {
const form = useZodForm(schema, { defaultValues: { email: "", cui: "" } })
return (
<form onSubmit={form.handleSubmit(onSave)} noValidate className="flex flex-col gap-4">
<Input label="Email" type="email" autoComplete="email" {...form.register("email")} error={fieldError(form, "email")} />
<Input label="Tax ID (CUI)" {...form.register("cui")} error={fieldError(form, "cui")} />
<Button type="submit" loading={form.formState.isSubmitting}>Save</Button>
</form>
)
}API
messagesdefault"en""ro" | "en"Demo only: which message set the validators use (the English defaults or VALIDATION_MESSAGES_RO).
minLengthdefault8numberv.password({ minLength }): the shortest password accepted.
minScoredefault2numberv.password({ score: scorePassword, minScore }): the weakest strength accepted (0 skips the check, 4 is Strong).
createValidators(messages?: Partial<ValidationMessages>) => ValidatorsZod schemas sharing one message set: text({ required, min, max }), name(), email(), password({ minLength, score, minScore }), phone({ country }), cui(), iban(), postalCode(), url(), otp(length), accept() (a ticked checkbox), number({ min, max }). Every field rule takes { required } and accepts "" when optional. v.messages is the merged set.
withMatch(schema: ZodObject, field: string, confirmField: string, message?: string) => ZodTypeAdds "confirmField must equal field" to an object schema, reported on the confirm field (password and its confirmation).
useZodForm(schema: ZodType, options?: UseFormProps) => UseFormReturnuseForm with the zod resolver and the library's timing: mode onTouched (an error appears once a field is left), then it updates as you type. Input and output types come from the schema.
fieldError(form: UseFormReturn, name: string) => string | undefinedThe error message of a field (dotted paths work), ready for a component's error prop: error={fieldError(form, "email")}.
simulateRequest<T>(ms?: number, options?: { fail?: string; value?: T; signal?: AbortSignal }) => Promise<T>A pretend request for demos and default handlers: resolves after ms (default 900), or rejects with fail as the message.
DEFAULT_VALIDATION_MESSAGESValidationMessagesThe English default messages createValidators merges yours over. Counted messages are functions: tooShort(min), otp(length).
VALIDATION_MESSAGES_ROValidationMessagesThe ready Romanian message set: pass it to createValidators for Romanian errors.
Examples
Bank details
IBAN and postal code rules; press Check to see the errors.
Files
- lib/form-validation.ts
FAQ
Is the Form validation helper free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Form validation?
Run npx wingo-ui@latest add form-validation. It also adds the Wingo UI item it builds on (Invoicing) and the npm packages react-hook-form, @hookform/resolvers, zod and libphonenumber-js. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/form-validation.
See also
Used in
More React hooks and utilities
Articles using this component
- React Multi Step Form with Zod, Saved Drafts and Motion
Component guides12 min read
- React Phone Input With Country Code and E.164 Value
Component guides8 min read
- IBAN Validation JavaScript: Mod 97, Regex and a React Field
Component guides12 min read
- React Form Components: Accessible Fields, Zod and Mobile
Component guides26 min read