Skip to content
Back to Learn
·6 min read

JSON Form Validation: React Hook Form, Formik, and Beyond

JSON is increasingly used to define form structures and validation rules in web applications. By using JSON schemas for form validation, developers can create consistent, maintainable, and type-safe forms across frontend frameworks. This guide covers form validation with JSON Schema, React Hook Form, Formik, Zod, and Yup, with practical examples and best practices. Use our JSON to React Hook Form and JSON to Formik tools to generate validation schemas instantly.

Why Use JSON for Form Validation?

ApproachProsCons
JSON SchemaLanguage-agnostic, reusable, self-documentingVerbose for simple forms
ZodTypeScript-first, concise syntax, excellent DXTypeScript-only
YupChainable API, good error messagesLarger bundle, slower than Zod
React Hook FormPerformant, minimal re-rendersRequires schema resolver
FormikMature, well-documentedMore boilerplate, more re-renders

Form Validation with JSON Schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "email": {
      "type": "string",
      "format": "email",
      "description": "User email address"
    },
    "password": {
      "type": "string",
      "minLength": 8,
      "pattern": "^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).+$",
      "description": "Password with uppercase, lowercase, and number"
    },
    "age": {
      "type": "integer",
      "minimum": 18,
      "maximum": 120
    },
    "country": {
      "type": "string",
      "enum": ["US", "CA", "UK", "AU", "Other"]
    },
    "agreeToTerms": {
      "type": "boolean",
      "const": true
    }
  },
  "required": ["email", "password", "agreeToTerms"]
}

React Hook Form with Zod Validation

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

const schema = z.object({
  email: z.string().email('Invalid email address'),
  password: z
    .string()
    .min(8, 'Password must be at least 8 characters')
    .regex(/[A-Z]/, 'Must contain an uppercase letter')
    .regex(/[a-z]/, 'Must contain a lowercase letter')
    .regex(/d/, 'Must contain a number'),
  age: z.number().min(18).max(120).optional(),
  country: z.enum(['US', 'CA', 'UK', 'AU', 'Other']),
  agreeToTerms: z.literal(true, {
    errorMap: () => ({ message: 'You must agree to terms' })
  })
});

function RegistrationForm() {
  const { register, handleSubmit, formState: { errors } } = useForm({
    resolver: zodResolver(schema)
  });

  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      <input {...register('email')} placeholder="Email" />
      {errors.email && <p>{errors.email.message}</p>}

      <input type="password" {...register('password')} placeholder="Password" />
      {errors.password && <p>{errors.password.message}</p>}

      <button type="submit">Register</button>
    </form>
  );
}

Formik with Yup Validation

import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';

const validationSchema = Yup.object({
  email: Yup.string().email('Invalid email').required('Required'),
  password: Yup.string()
    .min(8, 'Too short')
    .matches(/[A-Z]/, 'Uppercase required')
    .matches(/[a-z]/, 'Lowercase required')
    .matches(/d/, 'Number required')
    .required('Required'),
  age: Yup.number().min(18, 'Must be 18+').max(120).nullable()
});

function RegistrationForm() {
  return (
    <Formik
      initialValues={{ email: '', password: '', age: '' }}
      validationSchema={validationSchema}
      onSubmit={(values) => console.log(values)}
    >
      <Form>
        <Field name="email" type="email" placeholder="Email" />
        <ErrorMessage name="email" component="div" />

        <Field name="password" type="password" placeholder="Password" />
        <ErrorMessage name="password" component="div" />

        <button type="submit">Register</button>
      </Form>
    </Formik>
  );
}

Validating Against JSON Schema in the Backend

// Node.js with Ajv
import Ajv from 'ajv';
import addFormats from 'ajv-formats';

const ajv = new Ajv({ allErrors: true });
addFormats(ajv);

const validate = ajv.compile(userSchema);

app.post('/api/users', (req, res) => {
  const valid = validate(req.body);
  if (!valid) {
    return res.status(422).json({
      error: 'Validation failed',
      details: validate.errors.map(err => ({
        path: err.instancePath,
        message: err.message,
        params: err.params
      }))
    });
  }
  // Process valid data
});

Generate Validation Schemas from JSON

Use our tools to generate validation schemas from sample JSON data:

Validation Error Formatting Best Practices

  • Display errors inline, next to the relevant field
  • Use clear, actionable error messages (not just "Invalid field")
  • Validate on blur and on change, not just on submit
  • Debounce async validation (e.g., email uniqueness checks)
  • Support both client-side and server-side validation with the same schema
  • Always validate JSON input server-side, even with client-side validation

Next Steps

Generate validation schemas from your JSON with JSON to React Hook Form, JSON to Formik, JSON to Zod Schema, or JSON Schema Generator.