DEV Community

Ibrahim Hz
Ibrahim Hz

Posted on

Forms Got You Frazzled? How to Take Control of Input Validation in React

Introduction

Forms and input validation are critical components of many React apps. Handling user input correctly is crucial for a positive user experience. Forms allow users to enter and submit data to your app. Input validation ensures the data users enter is formatted and structured properly before being submitted to the server.

This guide will provide a comprehensive, step-by-step overview of working with forms and input validation in React. We'll start from the basics, setting up a simple form with an input field, then progressively add more complex features:

  • Tracking form state in React
  • Submitting the form and handling the submission
  • Validating form fields and inputs
  • Displaying user-friendly error messages
  • Redirecting after a successful form submission

By the end, you'll have a solid understanding of forms and input validation in React. You'll be able to build React forms with robust validation and error handling, ensuring your users enter problem-free data. Let's get started!

Setting Up a Basic Form

React makes it easy to set up basic forms that can handle user input. Here are the key steps:

  1. Create a component to hold your form. This is usually done in its own component, rather than mixing it in with other UI elements:
import React from 'react';

function MyForm() {

  return (
    <form>
      // form fields go here
    </form>
  );
}

export default MyForm;

Enter fullscreen mode Exit fullscreen mode
  1. Add a state hook to track form data. For example:
import { useState } from 'react';

function MyForm() {

  const [formData, setFormData] = useState({
    name: '',
    email: ''
  });

  return (
    // form JSX
  );
}

Enter fullscreen mode Exit fullscreen mode
  1. Add onChange handlers to form fields that call setFormData to update the state as the user types. For example:
<input
  type="text"
  name="name"
  value={formData.name}
  onChange={(e) => setFormData({...formData, name: e.target.value})}
/>

Enter fullscreen mode Exit fullscreen mode
  1. Access the final form values from formData before submitting.

That covers the basics of wiring up a form to track user input with React state. Next we'll look at handling form submission.

Tracking Form State

React uses state to track and manage form data. Here's how to use state with forms:

  • Create a component state object to hold the form data, for example:
state = {
  name: '',
  email: ''
}

Enter fullscreen mode Exit fullscreen mode
  • Add a value attribute to each form input that maps to the state:
<input
  type="text"
  value={this.state.name}
/>

Enter fullscreen mode Exit fullscreen mode
  • Update state on each change with onChange:
handleChange = (e) => {
  this.setState({[e.target.name]: e.target.value});
}

Enter fullscreen mode Exit fullscreen mode
<input
  name="name"
  onChange={this.handleChange}
/>

Enter fullscreen mode Exit fullscreen mode
  • The form data will now be stored in state and updated with each change.
  • Access the final values on submit via this.state.

This allows you to track all form data in state, eliminating the need to manage each input separately. The state serves as the "source of truth" for the form.

Handling Form Submission

When the user clicks the submit button, you'll want to send the form data to your server. In React, the standard way to achieve this is by using fetch() or a library like Axios to make an HTTP request.

Here are the main steps for handling form submission:

  1. Prevent the default form submit behavior. When the submit button is clicked, the browser will try to send a POST request which will reload the page. You need to call event.preventDefault() in the submit handler to prevent this.
  2. Get the form data from state. You stored the form data in component state as the user filled out the fields, so you just need to access it from this.state.
  3. Send the form data to the server. Use fetch() or Axios to make a POST request and send the data to the API endpoint you want to submit to. The endpoint should accept and process the data.
  4. Clear the form. After a successful submission, reset the form state by clearing the fields. You can set this.setState({field1: '', field2: ''}) to blank out the values.
  5. Show a success message. Let the user know the form submitted successfully by displaying a message.
  6. Handle errors. If the submission fails, show an error message from the response.

So in summary, prevent the default submit, grab the data from state, make the POST request, reset state, and update the UI accordingly. This will provide a complete submission flow for your form.

Validation - Required Fields

Validating that required fields are filled out before submitting a form is crucial. You don't want users to be able to submit your form without completing all the necessary fields.

React makes validating required fields easy. Here's one way to do it:

First, setup state to track each field value and whether it has been touched/changed. For example:

const [name, setName] = useState('');
const [nameTouched, setNameTouched] = useState(false);

const [email, setEmail] = useState('');
const [emailTouched, setEmailTouched] = useState(false);

Enter fullscreen mode Exit fullscreen mode

Then on your input, set onBlur to call setNameTouched(true) when focused out. And onChange to update the value state.

<input
  value={name}
  onChange={(e) => setName(e.target.value)}
  onBlur={() => setNameTouched(true)}
/>

Enter fullscreen mode Exit fullscreen mode

Now when validating on form submit, just check if (!name && nameTouched) to see if the field is empty and has been touched. If so, set an error state for that input.

This allows you to keep track of field state as well as validate on submit. The key is wiring up the onBlur and onChange handlers.

You can also disable the submit button until all required fields are valid to prevent submission. Overall this provides a smooth user experience for required fields.

Validation - Field Format

Validating that user input matches the expected format, like email addresses or phone numbers, is important for ensuring your data is clean. React offers some helpful tools here.

You can use regular expressions (regex) to define a pattern that input must match. For example, to validate an email input you could do:

const emailRegex = /^\\S+@\\S+\\.\\S+$/;

const validateEmail = (email) => {
  return emailRegex.test(email);
}

Enter fullscreen mode Exit fullscreen mode

The regex checks for a string with something before and after the @ sign, and a period after that.

To integrate this into your form validation, you'd simply call the function and check the return value before allowing submission.

Another option is using validator libraries like validator.js. This contains pre-built validation functions for common formats:

import validator from 'validator';

const validateEmail = (email) => {
  return validator.isEmail(email);
}

Enter fullscreen mode Exit fullscreen mode

This abstracts away the regex syntax with simple method calls.

Whichever approach you take, be sure to clearly communicate invalid formats to the user. Display a relevant error message by the field or disable the submit button when format validation fails.

Proper formatting will ensure you get clean data submitted to your app.

Validation - Field Length

Validating the length of input fields is important to ensure users provide values according to the required length. For example, you may want to validate that a username is between 5-20 characters.

To validate field length in React, you can use the minLength and maxLength attributes on input fields along with custom validation logic.

Here is an example:

<input
  type="text"
  id="username"
  minLength={5}
  maxLength={20}
/>

Enter fullscreen mode Exit fullscreen mode

This will add basic HTML5 validation to restrict the length. However, you still need custom validation to show error messages and prevent form submission.

To do this, you can check the length of the input value in your validation logic:

const validate = () => {

  if(username.length < 5 || username.length > 20) {
    // show error
  } else {
    // allow submit
  }

}

Enter fullscreen mode Exit fullscreen mode

You would run this validation on form submit and on each change of the input to provide real-time feedback.

Some key points for field length validation:

  • Use HTML attributes for basic length validation
  • Check length in custom logic to handle errors and submission
  • Validate on both submit and on change of the input
  • Show clear error messages if length requirement not met
  • Allow valid length inputs to submit the form

Properly validating field length ensures your users provide the expected data format and avoids submitting incorrect or incomplete data.

Real-time Validation

Validating input as soon as a user types is more user-friendly than displaying errors after submission. It provides immediate feedback so the user can correct mistakes early.

React allows us to validate each field on change by attaching an onChange handler to form inputs.

function Form() {

  const [firstName, setFirstName] = useState('');

  const handleFirstNameChange = (e) => {
    setFirstName(e.target.value);

    // Validate
    if(!e.target.value) {
      setFirstNameError('First name is required');
    } else {
      setFirstNameError('');
    }

  }

  return (
    <input
      name="firstName"
      value={firstName}
      onChange={handleFirstNameChange}
    />
  )

}

Enter fullscreen mode Exit fullscreen mode

The onChange handler calls setState to update the input value, then runs validation logic to check if the field is empty. If invalid, it displays an error by updating state.

This allows the component to re-render in real-time as the user types. Errors display instantly instead of on a submit event.

The same pattern can be followed for other fields like emails and phone numbers. Regular expressions or length checks can validate the format in real-time.

Real-time validation leads to a better user experience. It also means less invalid submissions to handle on the server side.

Error Messages

Handling and displaying validation errors to users is a key part of creating a good form experience. You want to clearly identify any issues with the data they've entered, while providing enough context and guidance to help them correct it.

There are a few best practices to follow when showing error messages:

  • Display errors next to the relevant form field. This allows users to quickly see what needs to be fixed, without having to search around.
  • Use clear, human-friendly language. Avoid over-technical messages that users may not understand.
  • Provide specific details about what exactly is wrong. Don't just say "Invalid input", explain what needs to be fixed.
  • Style errors visually to stand out. Red text and icons are common. But don't overdo it - you don't want to punish users.
  • Only show errors after a user has tried to submit the form. Don't interrupt them during normal typing.
  • If there are multiple errors, display them all at once. Don't make the user fix one at a time.
  • Ensure errors don't disappear until the user has fixed each issue. Keep errors displayed until the data is valid.
  • Give guidance on how to resolve the error if it's not obvious. For example, show format requirements or field length rules.
  • Be brief yet helpful. Find a balance between enough detail and too much text overload.

Adhering to these best practices will ensure the errors you display help guide users in a friendly way. Well-designed errors create a smooth, intuitive form experience.

Submission Redirect

Redirecting the user after a successful form submission is a common requirement. You'll usually want to show a confirmation message, return to the home page, or redirect elsewhere in the application.

React Router's useHistory hook provides a simple way to redirect after a form submits. For example:

import { useHistory } from 'react-router-dom';

function Form() {

  const history = useHistory();

  const handleSubmit = () => {
    // Submit form

    history.push('/submitted');
  }

  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
    </form>
  );
}

Enter fullscreen mode Exit fullscreen mode

When the form is submitted, handleSubmit will redirect to the /submitted route to show a confirmation page.

You can also pass state to the redirect:

history.push('/submitted', {
  name: formData.name
});

Enter fullscreen mode Exit fullscreen mode

This state can then be accessed from the redirected page.

To redirect back to the homepage, you'd use:

history.push('/');

Enter fullscreen mode Exit fullscreen mode

Overall, React Router's useHistory hook provides a straightforward way to redirect users after a successful form submission. Just call history.push() within your submit handler to send users to a confirmation page or elsewhere in your app.

That’s it for this article! I hope you enjoyed it and leave a few claps 👏 if you did. Follow me for more full stack devlopment articles and comment for any feedback you might have about this article.
I‘m Mohammed Ibrahim aka ibrahimhz. You can find me on LinkedIn or maybe follow me on GitHub as well.

Top comments (0)