Custom Form Validation Without External Libraries

Loading

In React, form validation is an essential part of ensuring that the data submitted by the user is correct and adheres to the required format. While libraries like Formik or React Hook Form simplify the process, you can easily implement custom form validation without using any external libraries by leveraging React’s built-in features like useState and useEffect.

In this guide, we will walk through creating a simple form with custom validation in React using state management and handling validation logic manually.

Steps to Implement Custom Form Validation

  1. Create the Form Component
  2. Set up State for Form Fields
  3. Create Validation Functions
  4. Handle Form Submission
  5. Display Validation Error Messages

1. Create the Form Component

Let’s start by setting up a basic form that includes common fields like username, email, and password.

import React, { useState } from 'react';

const CustomForm = () => {
  // Step 2: Setting up state for form fields
  const [formData, setFormData] = useState({
    username: '',
    email: '',
    password: '',
  });

  const [errors, setErrors] = useState({
    username: '',
    email: '',
    password: '',
  });

  const [isSubmitting, setIsSubmitting] = useState(false);

  // Step 3: Create validation functions
  const validate = () => {
    let tempErrors = {};
    let isValid = true;

    if (!formData.username) {
      tempErrors.username = 'Username is required';
      isValid = false;
    } else if (formData.username.length < 3) {
      tempErrors.username = 'Username must be at least 3 characters';
      isValid = false;
    }

    if (!formData.email) {
      tempErrors.email = 'Email is required';
      isValid = false;
    } else if (!/\S+@\S+\.\S+/.test(formData.email)) {
      tempErrors.email = 'Email is not valid';
      isValid = false;
    }

    if (!formData.password) {
      tempErrors.password = 'Password is required';
      isValid = false;
    } else if (formData.password.length < 6) {
      tempErrors.password = 'Password must be at least 6 characters';
      isValid = false;
    }

    setErrors(tempErrors);
    return isValid;
  };

  // Step 4: Handle form submission
  const handleSubmit = (event) => {
    event.preventDefault();

    // Check for validation
    if (validate()) {
      setIsSubmitting(true);

      // Simulate form submission
      setTimeout(() => {
        alert('Form submitted successfully!');
        setIsSubmitting(false);
      }, 1000);
    } else {
      alert('Please fix the errors before submitting.');
    }
  };

  // Handle input changes
  const handleChange = (event) => {
    const { name, value } = event.target;
    setFormData((prevState) => ({
      ...prevState,
      [name]: value,
    }));
  };

  return (
    <div>
      <h1>Custom Form Validation</h1>
      <form onSubmit={handleSubmit}>
        <div>
          <label>Username</label>
          <input
            type="text"
            name="username"
            value={formData.username}
            onChange={handleChange}
          />
          {errors.username && <p style={{ color: 'red' }}>{errors.username}</p>}
        </div>

        <div>
          <label>Email</label>
          <input
            type="email"
            name="email"
            value={formData.email}
            onChange={handleChange}
          />
          {errors.email && <p style={{ color: 'red' }}>{errors.email}</p>}
        </div>

        <div>
          <label>Password</label>
          <input
            type="password"
            name="password"
            value={formData.password}
            onChange={handleChange}
          />
          {errors.password && <p style={{ color: 'red' }}>{errors.password}</p>}
        </div>

        <button type="submit" disabled={isSubmitting}>
          {isSubmitting ? 'Submitting...' : 'Submit'}
        </button>
      </form>
    </div>
  );
};

export default CustomForm;

2. State Setup for Form Fields

We use the useState hook to manage the form data. Here’s a breakdown:

  • formData: Holds the current values for the form fields (username, email, password).
  • errors: Holds error messages for each field.
  • isSubmitting: Tracks the submission state to disable the submit button while submitting.

3. Create Validation Functions

The validate function checks each field for validity:

  • It ensures that the username is not empty and has at least 3 characters.
  • It ensures that the email is not empty and is in the correct format.
  • It ensures that the password is not empty and has at least 6 characters.

If any of these conditions fail, we set the corresponding error message in the errors state.

4. Handle Form Submission

The handleSubmit function is triggered when the user submits the form. It prevents the default form submission and:

  • Validates the form by calling validate().
  • If the validation passes, it simulates a successful form submission (with setTimeout).
  • If there are validation errors, it alerts the user and prevents submission.

5. Display Validation Error Messages

If a field has an error, we display the error message beneath the input field. We conditionally render these messages based on whether the respective field in the errors object contains a message.

6. Handling Input Changes

The handleChange function updates the form field value as the user types in the input field. We also ensure that the respective field value in formData is updated.

7. Disabling Submit Button While Submitting

To improve the user experience, we disable the submit button while the form is being submitted, indicated by the isSubmitting state.

Full Example: Complete Form with Custom Validation

import React, { useState } from 'react';

const CustomForm = () => {
  const [formData, setFormData] = useState({
    username: '',
    email: '',
    password: '',
  });

  const [errors, setErrors] = useState({
    username: '',
    email: '',
    password: '',
  });

  const [isSubmitting, setIsSubmitting] = useState(false);

  const validate = () => {
    let tempErrors = {};
    let isValid = true;

    if (!formData.username) {
      tempErrors.username = 'Username is required';
      isValid = false;
    } else if (formData.username.length < 3) {
      tempErrors.username = 'Username must be at least 3 characters';
      isValid = false;
    }

    if (!formData.email) {
      tempErrors.email = 'Email is required';
      isValid = false;
    } else if (!/\S+@\S+\.\S+/.test(formData.email)) {
      tempErrors.email = 'Email is not valid';
      isValid = false;
    }

    if (!formData.password) {
      tempErrors.password = 'Password is required';
      isValid = false;
    } else if (formData.password.length < 6) {
      tempErrors.password = 'Password must be at least 6 characters';
      isValid = false;
    }

    setErrors(tempErrors);
    return isValid;
  };

  const handleSubmit = (event) => {
    event.preventDefault();

    if (validate()) {
      setIsSubmitting(true);

      setTimeout(() => {
        alert('Form submitted successfully!');
        setIsSubmitting(false);
      }, 1000);
    } else {
      alert('Please fix the errors before submitting.');
    }
  };

  const handleChange = (event) => {
    const { name, value } = event.target;
    setFormData((prevState) => ({
      ...prevState,
      [name]: value,
    }));
  };

  return (
    <div>
      <h1>Custom Form Validation</h1>
      <form onSubmit={handleSubmit}>
        <div>
          <label>Username</label>
          <input
            type="text"
            name="username"
            value={formData.username}
            onChange={handleChange}
          />
          {errors.username && <p style={{ color: 'red' }}>{errors.username}</p>}
        </div>

        <div>
          <label>Email</label>
          <input
            type="email"
            name="email"
            value={formData.email}
            onChange={handleChange}
          />
          {errors.email && <p style={{ color: 'red' }}>{errors.email}</p>}
        </div>

        <div>
          <label>Password</label>
          <input
            type="password"
            name="password"
            value={formData.password}
            onChange={handleChange}
          />
          {errors.password && <p style={{ color: 'red' }}>{errors.password}</p>}
        </div>

        <button type="submit" disabled={isSubmitting}>
          {isSubmitting ? 'Submitting...' : 'Submit'}
        </button>
      </form>
    </div>
  );
};

export default CustomForm;

Leave a Reply

Your email address will not be published. Required fields are marked *