Handling Forms in React Applications

Have you ever visited an online shopping website, for example?

These websites typically have all kinds of products you can pick, add to your cart, and track the total amount of the things you plan to purchase. All before making the purchase, of course.

Somewhere in the checkout section of these websites, there is usually a section where you fill in your address, credit/debit card information and all the other relevant kinds of data that help the shipping company bring your purchase to your doorstep.

To cut a long story short, this section in the shopping website’s checkout section is called a form.

Put simply, forms are an integral part of any interactive user interface. You can find them on all kinds of websites from school websites to hospital appointment booking websites to shopping websites.

They are used to collect user input, such as text, numbers, and selections, and submit that data to a server for processing.

That is not to say that passing data to servers is all forms are used for. They are also applied to user authentication, data entry, and online shopping.

In this article, we will take a deep dive into forms in general, and how they are created and applied to react applications.

At the end of the page, you would have the necessary skills and understanding to create, pull data from, and even modify forms in react applications.

Forms In HTML versus React

As mentioned earlier, forms are a collection of input fields such as text boxes, radio buttons, checkboxes, and select boxes, that allow users to enter data and submit it to a server.

In regular HTML, forms are defined using the <form> element, which contains one or more input fields, and a submit button. When the user submits the form, the browser sends a request to the server, with the form data encoded in the URL or the request body.

A good example is:

<form action="/submit" method="post">

  <label for="name">Name:</label>

  <input type="text" id="name" name="name" required>



  <label for="email">Email:</label>

  <input type="email" id="email" name="email" required>



  <label for="message">Message:</label>

  <textarea id="message" name="message" required></textarea>



  <button type="submit">Submit</button>

</form>

This form includes three fields for name, email, message, and a submit button. It also includes the “required” attribute on each input field to ensure that the user must fill in all fields before submitting the form.

When the form is submitted, it will be sent to the /submit endpoint of whatever data handling API your application uses, through the POST method.

In React applications, however, forms are handled differently than in traditional web development. In React, forms are considered components, and they are managed by the state of the parent component.

Consider this example of a simple react form component:

import React, { useState } from 'react';

function ContactForm() {

  const [formData, setFormData] = useState({

    name: '',

    email: '',

  });

  const handleInputChange = (event) => {

    const { name, value } = event.target;

    setFormData({ ...formData, [name]: value });

  };

  const handleSubmit = (event) => {

    event.preventDefault();

    console.log(formData);

    // Perform form submission logic here

  };

  return (

    <form onSubmit={handleSubmit}>

      <label htmlFor="name">Name:</label>

      <input

        type="text"

        id="name"

        name="name"

        value={formData.name}

        onChange={handleInputChange}

        required

      />

      <label htmlFor="email">Email:</label>

      <input

        type="email"

        id="email"

        name="email"

        value={formData.email}

        onChange={handleInputChange}

        required

      />

      <button type="submit">Submit</button>

    </form>

  );

}

export default ContactForm;

Taking a good look at the code example above, we can already see some core differences between a react form component and a plain HTML component.

Some of these differences we’ll address in the coming sections, and others you may already have figured out.

In all, proper form handling is crucial in web development, as it ensures that the user input is valid and secure. Improper form handling can lead to security vulnerabilities, such as cross-site scripting (XSS) attacks, user errors, and a host of other things that can easily go wrong.

How Are Forms Handled In React Applications?

In React applications, forms are managed using the component’s state.

When the user interacts with the form, such as by typing in a text box or selecting an option, the state of the form is updated with each keystroke. And when the user submits the form, the form data is extracted from the state and sent to the server.

Explaining things like this makes form data handling seem simple.

And maybe it is. However, there are several processes, conventions and code patterns involved in between.

To handle forms in React, we use the “controlled component pattern”.

React's controlled component pattern is an approach to form handling where the values of form elements like input, select, and textarea are controlled by React component state. In other words, instead of the form elements managing their own state, React manages the state of the form elements through its component state.

To use controlled components in React, we need to define state variables that hold the values of the form elements, and then define event handlers that update the state variables in response to user input. These state variables and event handlers are passed as props to the form elements.

Here's an example of a controlled component in React, using a text input field:

import React, { useState } from 'react';



function Form() {

  const [inputValue, setInputValue] = useState('');



  const handleSubmit = (event) => {

    event.preventDefault();

    // submit the form data

  };



  const handleInputChange = (event) => {

    setInputValue(event.target.value);

  };



  return (

    <form onSubmit={handleSubmit}>

      <label>

        Name:

        <input type="text" value={inputValue} onChange={handleInputChange} />

      </label>

      <button type="submit">Submit</button>

    </form>

  );

}

In this example,

  1. The useState() hook is used to define a state variable inputValue that holds the value of the input field. The initial value of inputValue is an empty string.

  2. Two event handlers are defined: handleSubmit() and handleInputChange(). handleSubmit is called when the form is submitted, and handleInputChange is called whenever the value of the input field changes.

  3. The Form component returns a JSX template that includes a form element with an onSubmit() event handler that calls handleSubmit.

  4. Inside the form element, there's a label element that contains a text label "Name:" and an input element for the user to enter their name. The input element is a controlled component, which means that its value is controlled by the inputValue state variable and its onChange event is handled by the handleInputChange function.

  5. Finally, there's a button element with a type of submit that triggers the handleSubmit function when clicked.

In summary, this code sets up a simple form with one input field and a submit button, using the controlled component pattern in React to manage the state of the input field. When the form is submitted, the handleSubmit function is called, and the form data can be sent to a server or used in some other way by the application.

Creating a form in React

In HTML, forms are created using the <form> element, which contains one or more form elements, such as input fields and buttons.

When the user submits the form, the browser sends a request to the server, with the form data encoded in the URL or the request body.

In React, we use JSX instead of plain HTML. JSX, which is a syntax extension for JavaScript allows us to write HTML-like code in our JavaScript files and looks an awful lot like HTML.

Using JSX to create a form in React

Here's an example of how to create a simple form in React using JSX:

import React from 'react';



function MyForm() {

  return (

    <form>

      <label>

        Name:

        <input type="text" name="name" />

      </label>

      <label>

        Email:

        <input type="email" name="email" />

      </label>

      <button type="submit">Submit</button>

    </form>

  );

}

In this example:

  1. The MyForm function is defined as a React component that returns a JSX template.

  2. The JSX template includes a form element that contains two label elements, each with an input element inside. The label elements provide text labels for each input field (Name and Email).

  3. The first input element has a type of text and a name attribute of name, which means that it will accept any text input and its value will be identified by the name "name" when the form is submitted.

  4. The second input element has a type of email and a name attribute of email, which means that it will only accept email input and its value will be identified by the name "email" when the form is submitted.

  5. Finally, there's a button element with a type of submit property that triggers the submission of the form data when clicked.

This code defines a basic form component in React with two input fields and a submit button. However, it does not handle any form submission or input validation logic.

Handling form input

In HTML, input elements are used to create form fields that allow the user to input data. These input elements include:

  1. text

  2. password

  3. checkbox

  4. radio

  5. select

  6. and file.

Each input element has its own set of attributes that determine its behaviour, such as name, value, type, placeholder, required, and disabled.

However, React’s JSX syntax allows us to encapsulate the behaviour and appearance of the input element to suit our needs.

Event handling in React and how to handle form input

In React, we handle events using event handlers.

Event handlers are functions that are called when an event is triggered. Events may include a button click, a form submission, or a key press.

Kind of similar to an alarm that lets your react application know that you pressed a button or moved your mouse, or hovered over an element.

React’s JSX allows us to attach event handlers to HTML elements using props like onClick, onSubmit, or onKeyPress among others.

Need an example of how to handle form input in React using event handlers?

Well, here you go:

import React, { useState } from 'react';



function MyForm() {

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



  const handleNameChange = (event) => {

    setName(event.target.value);

  };



  return (

    <form>

      <label>

        Name:

        <input type="text" value={name} onChange={handleNameChange} />

      </label>

    </form>

  );

}

In this example:

  1. We define a component called MyForm, which uses the useState hook to create a state variable called name.

  2. We also define an event handler called handleNameChange, which is called whenever the user types in the input field.

  3. We update the value of the name with the new input value using setName.

  4. We attach the onChange event handler to the input element using the props syntax.

In summary, whenever the user types in the input field, the handleNameChange function is called, which updates the state variable name.

Form State management in React

In React, we use state management to keep track of the data that changes over time, such as user input in a form.

In the following example, we use the useState hook to create state variables and update the state using state update functions like setState or setName.

Below is an example of how to manage form input using state management in React:

import React, { useState } from 'react';



function MyForm() {

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

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



  const handleNameChange = (event) => {

    setName(event.target.value);

  };



  const handleEmailChange = (event) => {

    setEmail(event.target.value);

  };



  const handleSubmit = (event) => {

    event.preventDefault();

    console.log('Name:', name);

    console.log('Email:', email);

  };



  return (

    <form onSubmit={handleSubmit}>

      <label>

        Name:

        <input type="text" value={name} onChange={handleNameChange} />

      </label>

      <label>

        Email:

        <input type="email" value={email} onChange={handleEmailChange} />

      </label>

      <button type="submit">Submit</button>

    </form>

  );

}

In this example:

  1. The code above defines a React component called MyForm which displays a form with two input fields for Name and Email, and a submit button.

  2. The state of the component is managed using the useState hook. It initializes two state variables, name and email, with empty strings using useState('').

  3. The handleNameChange and handleEmailChange functions update the state of the corresponding input fields whenever there is a change in their value. They are passed to the onChange event of the input fields.

  4. The handleSubmit function is called when the submit button is clicked. It prevents the default form submission behaviour and logs the current values of the name and email state variables to the console.

  5. Finally, the component returns a form element with two label elements that have input elements inside.

The value attribute of the input elements is set to the corresponding state variable, and the onChange attribute is set to call the corresponding state update function. The onSubmit attribute of the form element is set to call the handleSubmit function when the form is submitted.

Form validation

Form validation is an important aspect react and web development in general because it ensures that the data entered by the user is correct and meets the required criteria.

For example, imagine a food ordering website that requires the user to input the number of ketchup sachets they want.

The form field for “amount of ketchup sachet(s)” is properly labelled. However, what happens if the user wants four sachets, and accidentally puts in “tomato”?

Whoever packs the customer's order in to-go bags would get really confused and may have to "wing things".

“Pack a tomato number of sachets of ketchup into customer twenty’s order”.

Pretty confusing, isn’t it?

The example above is a lighter one. It is easy to imagine all the things that could go wrong if this mistake came from a hospital appointment booking or a school website.

Imagine filling in the wrong details in the “allergies” section of a food ordering app.

In all, form validation prevents errors and improves the user experience by providing helpful feedback to the user.

It also ensures that the data entered into the system is accurate and consistent, which is essential for data integrity and security, as well as proper data processing where necessary

Types of form validation (client-side versus server-side)

There are two types of form validation:

Client-Side Validation

Client-side validation is performed on the client side, which means that the validation is done on the user's computer or device.

This type of validation is fast and responsive because it happens in real-time as the user enters data into the form.

The major drawback of this method, however, is that client-side validation can be bypassed by malicious users who have the skills and intent to manipulate the HTML and JavaScript code.

Server-Side Validation

Server-side validation, on the other hand, is performed on the server side, which means that the validation is done on the web server.

This type of validation is more secure because it cannot be bypassed by users. However, it is slower because it requires a round-trip to the server.

Client-side form validation in React

In React, we can perform client-side form validation using a combination of HTML5 validation attributes and custom JavaScript code.

Here's an example of how to perform client-side form validation in React using HTML5 validation attributes:

import React, { useState } from 'react';



function MyForm() {

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

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



  const handleNameChange = (event) => {

    setName(event.target.value);

  };



  const handleEmailChange = (event) => {

    setEmail(event.target.value);

  };



  const handleSubmit = (event) => {

    event.preventDefault();

    console.log('Name:', name);

    console.log('Email:', email);

  };



  return (

    <form onSubmit={handleSubmit}>

      <label>

        Name:

        <input type="text" value={name} onChange={handleNameChange} required />

      </label>

      <label>

        Email:

        <input type="email" value={email} onChange={handleEmailChange} required />

      </label>

      <button type="submit">Submit</button>

    </form>

  );

}

In this example, we use the required attribute to make the Name and Email fields required. This means that the user must fill in these fields before submitting the form.

We can also use other HTML5 validation attributes, such as pattern, min, max, step, maxlength, and minlength, to validate the input data.

We can also use custom JavaScript code to perform more complex form validation, such as checking if the email address is valid, or if the password meets the required criteria. We can do this by attaching event handlers to the input fields and using conditional statements to check the input data.

import React, { useState } from 'react';

function MyForm() {
  const [password, setPassword] = useState('');

  const handlePasswordChange = (event) => {
    setPassword(event.target.value);
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    console.log('Password:', password);
  };

  const isPasswordValid = () => {
    return password.length >= 8 && /[a-z]/.test(password) && /[A-Z]/.test(password) && /[0-9]/.test(password);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Password:
        <input type="password" value={password} onChange={handlePasswordChange} />
</label>
<button type="submit" disabled={!isPasswordValid()}>
Submit
</button>
</form>
);
}

export default MyForm

Submitting a form in React

In React, we can submit a form using the onSubmit event handler. When the user clicks the submit button or presses the enter key while focused on an input field, the onSubmit event is triggered.

Pretty simple, isn’t it?

We can handle the onSubmit event by attaching an event handler function to the form element as illustrated below.

import React, { useState } from 'react';



function MyForm() {

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

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



  const handleNameChange = (event) => {

    setName(event.target.value);

  };



  const handleEmailChange = (event) => {

    setEmail(event.target.value);

  };



  const handleSubmit = (event) => {

    event.preventDefault();

    console.log('Name:', name);

    console.log('Email:', email);

    // Here you can add your code to submit the form data

  };



  return (

    <form onSubmit={handleSubmit}>

      <label>

        Name:

        <input type="text" value={name} onChange={handleNameChange} />

      </label>

      <label>

        Email:

        <input type="email" value={email} onChange={handleEmailChange} />

      </label>

      <button type="submit">Submit</button>

    </form>

  );

}

In this example, we first import React and useState hook. We then define a functional component called MyForm, which uses two pieces of state to keep track of the input values for name and email, and two functions to update those values.

The component also has an onSubmit event handler defined by the handleSubmit function, which is called when the form is submitted.

This handleSubmit function simply logs values to the console but can be filled with code that passes data to a server.

Form submission with Axios and AJAX requests

In some cases, we may need to submit the form data to a server using AJAX (Asynchronous JavaScript and XML) requests.

In summary, AJAX requests allow us to submit form data without reloading the page, which provides a smoother user experience. But more of that in a later article.

However, here's an example of how to handle form submission with AJAX requests in React:

import React, { useState } from 'react';

import axios from 'axios';



function MyForm() {

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

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



  const handleNameChange = (event) => {

    setName(event.target.value);

  };



  const handleEmailChange = (event) => {

    setEmail(event.target.value);

  };



  const handleSubmit = (event) => {

    event.preventDefault();

    console.log('Name:', name);

    console.log('Email:', email);



    axios.post('/api/formdata', {

      name: name,

      email: email,

    })

    .then((response) => {

      console.log(response);

    })

    .catch((error) => {

      console.log(error);

    });

  };



  return (

    <form onSubmit={handleSubmit}>

      <label>

        Name:

        <input type="text" value={name} onChange={handleNameChange} />

      </label>

      <label>

        Email:

        <input type="email" value={email} onChange={handleEmailChange} />

      </label>

      <button type="submit">Submit</button>

    </form>

  );

}

In this example:

1. We import the axios library at the top of our file using the following statement:

import axios from 'axios';

2. We can then use the axios object to make HTTP requests to our server.

3. We use the `axios library to make a POST request to the /api/formdata endpoint with the form data as the request body.

4. We handle the success and error responses using the then() and catch() methods, respectively.

Conclusion

Proper form handling is crucial in creating interactive and user-friendly web applications with React.

We have explained React's controlled component approach earlier in this article, and how we can use it to perform form handling.

We can also easily manage form input and perform client-side form validation using this method, making our application more responsive and efficient.

In this article, we covered the basics of handling forms in React applications, including creating a form, handling form input, performing form validation, and submitting a form using the onSubmit event handler or AJAX requests.

And with this understanding of the key concepts, you can build robust and effective forms in your React applications.

Check out the following resources:

Here are some of the top recommended articles you might consider taking a look at, for further reading:

  • React official documentation on forms here

  • "Handling Forms in React" tutorial by Robin Wieruch here

  • "Formik: Build Forms in React, Without the Hassle" tutorial by Gabe Ragland here

  • "React Hook Form - Simple React forms validation" tutorial by Mateusz Szostek here