React Form Validation with Custom Hook

Validate React form fields using a custom useForm hook with real-time error messages, submission blocking, and TypeScript type safety for form data and.

Typescript React Form Validation

Code

snippet
import { useState, useCallback } from 'react';

interface ValidationRule {
  required?: boolean;
  minLength?: number;
  pattern?: RegExp;
  message: string;
}

export function useForm<T extends Record<string, string>>(
  initialValues: T,
  rules: Partial<Record<keyof T, ValidationRule[]>>,
) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState<Partial<Record<keyof T, string>>>({});

  const validate = useCallback(
    (name: keyof T, value: string) => {
      const fieldRules = rules[name];
      if (!fieldRules) return '';
      for (const rule of fieldRules) {
        if (rule.required && !value) return rule.message;
        if (rule.minLength && value.length < rule.minLength) return rule.message;
        if (rule.pattern && !rule.pattern.test(value)) return rule.message;
      }
      return '';
    },
    [rules],
  );

  const handleChange = (name: keyof T, value: string) => {
    setValues((prev) => ({ ...prev, [name]: value }));
    setErrors((prev) => ({ ...prev, [name]: validate(name, value) }));
  };

  const isValid = Object.keys(rules).every((key) => !validate(key as keyof T, values[key as keyof T]));

  return { values, errors, handleChange, isValid };
}