typescriptintermediate

useFormValidation Hook

Lightweight form validation hook with field-level errors, touched tracking, and submit handling.

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

type Errors<T> = Partial<Record<keyof T, string>>;
type Validator<T> = (values: T) => Errors<T>;

export function useFormValidation<T extends Record<string, unknown>>(
  initial: T,
  validate: Validator<T>
) {
  const [values, setValues] = useState(initial);
  const [errors, setErrors] = useState<Errors<T>>({});
  const [touched, setTouched] = useState<Partial<Record<keyof T, boolean>>>({});

  const handleChange = useCallback(
    (field: keyof T, value: T[keyof T]) => {
      setValues((prev) => ({ ...prev, [field]: value }));
      setTouched((prev) => ({ ...prev, [field]: true }));
    },
    []
  );

  const handleSubmit = useCallback(
    (onSubmit: (v: T) => void) => {
      const errs = validate(values);
      setErrors(errs);
      if (Object.keys(errs).length === 0) onSubmit(values);
    },
    [values, validate]
  );

  return { values, errors, touched, handleChange, handleSubmit };
}

Use Cases

  • Contact forms
  • Registration forms
  • Settings pages

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.