Forms and Controlled components

Forms are essential for collecting user inputs in web applications. In React, forms work differently compared to traditional HTML forms because of the component-based architecture. This chapter will delve into the concept of controlled components, which is the preferred way to manage form inputs in React. We will cover the basics of controlled components, handle different types of form elements, validate inputs, and explore advanced form handling techniques.

Basics of Controlled Components

Controlled components are those where React controls the form inputs by keeping the form data in the component’s state. This approach allows React to have full control over the form elements, making it easier to manage and validate form data.

Understanding Controlled Components

In a controlled component, the form data is handled by the component’s state. This means that the value of an input element is always driven by the React state.

				
					import React, { useState } from 'react';

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

  const handleChange = (e) => {
    setInputValue(e.target.value);
  };

  return (
    <div>
      <label>
        Name:
        <input type="text" value={inputValue} onChange={handleChange} />
      </label>
      <p>Your input: {inputValue}</p>
    </div>
  );
}

export default SimpleForm;

				
			

Explanation:

  • The inputValue state stores the current value of the input field.
  • The handleChange function updates the state whenever the input value changes.
  • The input element’s value prop is tied to the state, making it a controlled component.
				
					<div>
  <label>
    Name:
    <input type="text" />
  </label>
  <p>Your input: </p>
</div>

				
			

When you type in the input field, the paragraph below it updates to show the current value.

Handling Different Types of Form Elements

React can handle various types of form elements including text inputs, checkboxes, radio buttons, and select dropdowns. Each type requires a slightly different handling approach.

Text Inputs

Text inputs are straightforward and are managed with a state variable and an onChange handler.

				
					import React, { useState } from 'react';

function TextInputForm() {
  const [text, setText] = useState('');

  const handleChange = (e) => {
    setText(e.target.value);
  };

  return (
    <form>
      <label>
        Text:
        <input type="text" value={text} onChange={handleChange} />
      </label>
      <p>Entered text: {text}</p>
    </form>
  );
}

export default TextInputForm;

				
			
				
					<form>
  <label>
    Text:
    <input type="text" />
  </label>
  <p>Entered text: </p>
</form>

				
			

Textareas

Textareas work similarly to text inputs but use the <textarea> element.

				
					import React, { useState } from 'react';

function TextareaForm() {
  const [text, setText] = useState('');

  const handleChange = (e) => {
    setText(e.target.value);
  };

  return (
    <form>
      <label>
        Description:
        <textarea value={text} onChange={handleChange} />
      </label>
      <p>Description: {text}</p>
    </form>
  );
}

export default TextareaForm;

				
			
				
					<form>
  <label>
    Description:
    <textarea></textarea>
  </label>
  <p>Description: </p>
</form>

				
			

Checkboxes

Checkboxes are a bit different because they deal with boolean values.

				
					import React, { useState } from 'react';

function CheckboxForm() {
  const [checked, setChecked] = useState(false);

  const handleChange = (e) => {
    setChecked(e.target.checked);
  };

  return (
    <form>
      <label>
        Accept Terms:
        <input type="checkbox" checked={checked} onChange={handleChange} />
      </label>
      <p>Accepted: {checked ? 'Yes' : 'No'}</p>
    </form>
  );
}

export default CheckboxForm;

				
			
				
					<form>
  <label>
    Accept Terms:
    <input type="checkbox" />
  </label>
  <p>Accepted: No</p>
</form>

				
			

Radio Buttons

Radio buttons are similar to checkboxes but typically used in groups where only one option can be selected.

				
					import React, { useState } from 'react';

function RadioButtonForm() {
  const [selectedOption, setSelectedOption] = useState('option1');

  const handleChange = (e) => {
    setSelectedOption(e.target.value);
  };

  return (
    <form>
      <label>
        Option 1:
        <input
          type="radio"
          value="option1"
          checked={selectedOption === 'option1'}
          onChange={handleChange}
        />
      </label>
      <label>
        Option 2:
        <input
          type="radio"
          value="option2"
          checked={selectedOption === 'option2'}
          onChange={handleChange}
        />
      </label>
      <p>Selected option: {selectedOption}</p>
    </form>
  );
}

export default RadioButtonForm;

				
			
				
					<form>
  <label>
    Option 1:
    <input type="radio" value="option1" />
  </label>
  <label>
    Option 2:
    <input type="radio" value="option2" />
  </label>
  <p>Selected option: option1</p>
</form>

				
			

Select Dropdowns

Select dropdowns involve a select element and multiple options.

				
					import React, { useState } from 'react';

function SelectForm() {
  const [selectedOption, setSelectedOption] = useState('option1');

  const handleChange = (e) => {
    setSelectedOption(e.target.value);
  };

  return (
    <form>
      <label>
        Choose an option:
        <select value={selectedOption} onChange={handleChange}>
          <option value="option1">Option 1</option>
          <option value="option2">Option 2</option>
          <option value="option3">Option 3</option>
        </select>
      </label>
      <p>Selected option: {selectedOption}</p>
    </form>
  );
}

export default SelectForm;

				
			
				
					<form>
  <label>
    Choose an option:
    <select>
      <option value="option1">Option 1</option>
      <option value="option2">Option 2</option>
      <option value="option3">Option 3</option>
    </select>
  </label>
  <p>Selected option: option1</p>
</form>

				
			

Handling Form Submission

When dealing with forms, handling the form submission event is crucial. This typically involves preventing the default form submission behavior and processing the form data.

Preventing Default Behavior

				
					import React, { useState } from 'react';

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

  const handleChange = (e) => {
    setInputValue(e.target.value);
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    alert(`Submitted value: ${inputValue}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" value={inputValue} onChange={handleChange} />
      </label>
      <button type="submit">Submit</button>
    </form>
  );
}

export default SubmissionForm;

				
			

Explanation:

  • The handleSubmit function prevents the default form submission and displays an alert with the input value.
				
					<form>
  <label>
    Name:
    <input type="text" />
  </label>
  <button type="submit">Submit</button>
</form>

				
			

Validating Form Inputs

Form validation ensures that the user inputs meet certain criteria before submission. This can be done using state and conditional rendering.

				
					import React, { useState } from 'react';

function ValidationForm() {
  const [email, setEmail] = useState('');
  const [error, setError] = useState('');

  const handleChange = (e) => {
    setEmail(e.target.value);
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!email.includes('@')) {
      setError('Invalid email address');
    } else {
      setError('');
      alert(`Submitted email: ${email}`);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Email:
        <input type="email" value={email} onChange={handleChange} />
      </label>
      {error && <p style={{ color: 'red' }}>{error}</p>}
      <button type="submit">Submit</button>
    </form>
  );
}

export default ValidationForm;

				
			

Explanation:

  • The error state holds the error message.
  • The handleSubmit function checks if the email contains an ‘@’ character and sets the error state accordingly.
				
					<form>
  <label>
    Email:
    <input type="email" />
  </label>
  <p style="color: red;"></p>
  <button type="submit">Submit</button>
</form>

				
			

Advanced Form Handling

For complex forms, you might need to manage multiple input fields and more advanced validation. Here’s an example of a more complex form.

Example: Complex Form with Multiple Inputs

				
					import React, { useState } from 'react';

function ComplexForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    age: ''
  });
  const [errors, setErrors] = useState({});

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

  const validate = () => {
    const newErrors = {};
    if (!formData.name) newErrors.name = 'Name is required';
    if (!formData.email.includes('@')) newErrors.email = 'Invalid email';
    if (!formData.age || isNaN(formData.age)) newErrors.age = 'Age must be a number';
    return newErrors;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const validationErrors = validate();
    if (Object.keys(validationErrors).length > 0) {
      setErrors(validationErrors);
    } else {
      setErrors({});
      alert(`Submitted data: ${JSON.stringify(formData)}`);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Name:
          <input
            type="text"
            name="name"
            value={formData.name}
            onChange={handleChange}
          />
        </label>
        {errors.name && <p style={{ color: 'red' }}>{errors.name}</p>}
      </div>
      <div>
        <label>
          Email:
          <input
            type="email"
            name="email"
            value={formData.email}
            onChange={handleChange}
          />
        </label>
        {errors.email && <p style={{ color: 'red' }}>{errors.email}</p>}
      </div>
      <div>
        <label>
          Age:
          <input
            type="text"
            name="age"
            value={formData.age}
            onChange={handleChange}
          />
        </label>
        {errors.age && <p style={{ color: 'red' }}>{errors.age}</p>}
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

export default ComplexForm;

				
			

Explanation:

  • formData state holds multiple input field values.
  • errors state holds error messages for each field.
  • handleChange function updates the specific field in the formData state.
  • validate function checks for validation errors.
  • handleSubmit function validates the form and either sets error messages or submits the data.
				
					<form>
  <div>
    <label>
      Name:
      <input type="text" name="name" />
    </label>
    <p style="color: red;"></p>
  </div>
  <div>
    <label>
      Email:
      <input type="email" name="email" />
    </label>
    <p style="color: red;"></p>
  </div>
  <div>
    <label>
      Age:
      <input type="text" name="age" />
    </label>
    <p style="color: red;"></p>
  </div>
  <button type="submit">Submit</button>
</form>

				
			

Forms and controlled components are fundamental in React for handling user input. By managing form data through the component state, React provides a robust way to handle and validate inputs. This chapter covered the basics of controlled components, handling different types of form elements, managing form submissions, validating inputs, and advanced form handling techniques. Mastering these concepts will enable you to create dynamic, interactive, and user-friendly forms in your React applications.Happy coding !❤️

Table of Contents