build-react-form-with-validation
Builds an accessible React form with React Hook Form and Zod schema validation, inline error messages and a loading submit state. Use when the user wants a signup, contact, checkout or settings form, form validation, required fields, or error messages under inputs.
Version 1.0 · Updated 2026-10-30
Install in Claude Code, Cursor or Codex (optional)
Only for AI coding tools that read skill folders. Run one line in a terminal, in your project folder. It downloads this skill's text files from TheSkillVault and nothing else; you can read them first with “View raw SKILL.md”.
Claude Code (all your projects)
curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/build-react-form-with-validation/raw' -o ~/'.claude/skills/build-react-form-with-validation/SKILL.md'Cursor (this project)
curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/build-react-form-with-validation/raw' -o '.cursor/skills/build-react-form-with-validation/SKILL.md'Codex and other Agent Skills tools (this project)
curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/build-react-form-with-validation/raw' -o '.agents/skills/build-react-form-with-validation/SKILL.md'
Or connect the whole library over MCP
Add TheSkillVault to Cursor or add this to your app's MCP settings (read-only; help):
{
"mcpServers": {
"theskillvault": {
"url": "https://theskillvault.ai/mcp"
}
}
}Build a React form with validation
When to use
- Any form with more than two fields, or any form that posts to an API.
- Replacing ad-hoc
useStateper field with one schema that is the single source of truth.
Steps
- Install:
npm i react-hook-form zod @hookform/resolvers. - Define the schema once and infer the type from it:
const Schema = z.object({
email: z.string().email("Enter a valid email"),
password: z.string().min(8, "At least 8 characters"),
});
type FormValues = z.infer<typeof Schema>;
- Wire the form:
useForm<FormValues>({ resolver: zodResolver(Schema), mode: "onBlur" }). - For each field render a
<label htmlFor>, the input with{...register("email")},aria-invalid={!!errors.email}andaria-describedby="email-error", and the error in<p id="email-error" role="alert">. - In
onSubmit, disable the button whileformState.isSubmitting, call the API, and map server errors back withsetError("email", { message }). - Re-use the same Zod schema on the server to validate the request body.
Gotchas
mode: "onChange"on every field feels nagging; validate on blur, re-validate on change after the first error.- Number inputs return strings: use
z.coerce.number(). - Never rely on client validation alone; always validate again on the server.
Example prompt
"Add a signup form with email and password that shows errors under each field."
Licence: CC BY 4.0. Attribution when you reuse it: From TheSkillVault, https://theskillvault.ai, CC BY 4.0