shadcn.io is an independent project built on shadcn/ui
Username, email, and age each fail with a sentence written for that rule, including an emoji. Username wants 3 to 20 letters, numbers, or underscores. Age must be a number from 13 to 120.
Use it when the stock error text is too blunt. The rules stay in Zod, not in the Input. In React, Ark UI only shows the message.
Installation
Usage
<form
className="w-full max-w-md"
noValidate
onSubmit={form.handleSubmit(onSubmit)}
>
<FieldGroup>
<Controller
control={form.control}
name="username"
render={({ field, fieldState }) => (
<Field invalid={fieldState.invalid}>
<FieldLabel>Username</FieldLabel>
<Input {...field} placeholder="cool_user123" />
<FieldDescription>Choose a unique username.</FieldDescription>
<FieldError>{fieldState.error?.message}</FieldError>
</Field>
)}
/>
<Controller
control={form.control}
name="email"
render={({ field, fieldState }) => (
<Field invalid={fieldState.invalid}>
<FieldLabel>Email</FieldLabel>
<Input {...field} placeholder="you@example.com" type="email" />
<FieldError>{fieldState.error?.message}</FieldError>
</Field>
)}
/>
<Controller
control={form.control}
{/* The rest of the file is under Installation. */}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.
API Reference
Field
Sets invalid={fieldState.invalid} and orientation="horizontal". The rest is on the Field page.
Input
Sets field, placeholder="cool_user123", placeholder="you@example.com", type="email", name={field.name} and onBlur={field.onBlur}. The rest is on the Input page.
Button
Sets type="submit". The rest is on the Button page.





