Frontend · How to use a skill

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

View raw SKILL.md

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 useState per field with one schema that is the single source of truth.

Steps

  1. Install: npm i react-hook-form zod @hookform/resolvers.
  2. 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>;
  1. Wire the form: useForm<FormValues>({ resolver: zodResolver(Schema), mode: "onBlur" }).
  2. For each field render a <label htmlFor>, the input with {...register("email")}, aria-invalid={!!errors.email} and aria-describedby="email-error", and the error in <p id="email-error" role="alert">.
  3. In onSubmit, disable the button while formState.isSubmitting, call the API, and map server errors back with setError("email", { message }).
  4. 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