Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Form examples ยท Validation

Custom Validation Messages Form for React

A sign-up form whose username, email and age rules each answer with a friendly custom message and an emoji.

Framework
UI library

Invalid input tells people nothing. Each rule in this form's Zod schema carries its own conversational message, such as "Come on, at least 3 characters! ๐Ÿ˜…", and the field's FieldError shows it under the input. Username, Email and Age are each a Field wired to React Hook Form by a Controller. Use it for consumer sign-ups or any form where friendlier errors help people finish.

Preview

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.
Use email insteadNo credit card

FAQ

Which username messages are in the schema?

.min(3) says "Come on, at least 3 characters! ๐Ÿ˜…", .max(20) says "Whoa there! Keep it under 20 characters. ๐Ÿ›‘", and .regex(/^[a-zA-Z0-9_]+$/) says "Letters, numbers, and underscores only, please! ๐Ÿ”ค". The FieldError shows the first one that fails.

What does a bad email say?

email is z.email("That doesn't look like an email address. ๐Ÿ“ง"). The form sets noValidate, so the browser's own email check doesn't get there first. Only Username has a description: "Choose a unique username."

Which age messages appear?

.min(13) says "You must be at least 13 years old. ๐Ÿšธ" and .max(120) says "Please enter a realistic age. ๐ŸŽ‚". Age is z.number with the error "Age must be a number! ๐Ÿ”ข" for anything that isn't a number.

What does a blank age produce?

age starts as undefined, and clearing the input sets it back to undefined, so a blank age shows "Age must be a number! ๐Ÿ”ข". It never turns into 0.

How is the age input set up?

It's an Input with type="number" and placeholder 25. Instead of spreading field, its onChange stores Number(event.target.value), or undefined when empty, and value is field.value ?? "".

When do these messages show?

mode is the default, so the schema first runs on submit. Sign Up is a type="submit" button, and onSubmit logs { age, email, username }, with age a number, once everything passes.