Form Libraries and Formik Integration

Forms are an integral part of web applications as they are used to capture user inputs, such as login credentials, feedback, search queries, etc. Handling forms in React can be challenging, especially as the complexity of forms increases. Luckily, various form libraries in the React ecosystem simplify this task. One of the most popular libraries is Formik, which helps manage form state, validation, and submission efficiently.

Introduction to Form Handling in React

Native Form Handling in React

React doesn’t come with built-in form management tools, but it provides the basics to manage form state using the component’s local state and event handlers. Here’s an example of handling forms in React without any external libraries:

				
					import React, { useState } from 'react';

function SimpleForm() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    alert(`Name: ${name}, Email: ${email}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>Name:</label>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <br />
      <label>Email:</label>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <br />
      <button type="submit">Submit</button>
    </form>
  );
}

export default SimpleForm;

				
			

Explanation:

  • We use useState hooks to manage the name and email fields.
  • The onChange event updates the state as the user types.
  • The handleSubmit function prevents the default form submission and handles the form data.

Output:

This form captures the user’s name and email, and upon submission, it displays an alert with the entered details. While this approach works fine for simple forms, as forms grow more complex (e.g., multiple fields, validation), managing everything manually can become cumbersome.

Why Use Form Libraries in React?

Handling form state and validation manually can lead to a lot of boilerplate code and potential errors. This is where form libraries come in. They help in managing complex form logic, including:

  • Handling multiple inputs.
  • Managing form state.
  • Implementing form validation (synchronous and asynchronous).
  • Handling form submission.
  • Displaying error messages.

Libraries like Formik, React Hook Form, and Redux Form are designed to address these challenges by reducing boilerplate code and providing an organized structure.

Introduction to Formik

What is Formik?

Formik is one of the most popular form libraries in the React ecosystem. It simplifies form management, including handling form state, validations, error messages, and submission, making it a preferred choice for React developers.

Some key features of Formik:

  • Manage form state: Easily track the state of form inputs.
  • Validation: Add validation logic easily (both sync and async).
  • Error handling: Manage error messages for fields.
  • Form submission: Handle the form submission process.
  • Integration with other validation libraries: Works seamlessly with libraries like Yup for schema-based validation.

How Formik Works

Formik operates by wrapping your form elements inside a component that tracks the form’s state and handles input changes and submissions. The basic components of Formik include:

  • Formik: The main component that manages form state.
  • Form: A wrapper for the form element.
  • Field: Used for rendering form inputs.
  • ErrorMessage: Displays validation error messages for individual fields.

Setting Up Formik in React

To get started with Formik, you need to install it:

				
					npm install formik

				
			

Basic Form with Formik

Let’s start with a simple form using Formik.

				
					import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';

function BasicForm() {
  return (
    <Formik
      initialValues={{ name: '', email: '' }}
      validate={(values) => {
        const errors = {};
        if (!values.name) {
          errors.name = 'Required';
        }
        if (!values.email) {
          errors.email = 'Required';
        } else if (
          !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
        ) {
          errors.email = 'Invalid email address';
        }
        return errors;
      }}
      onSubmit={(values, { setSubmitting }) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          setSubmitting(false);
        }, 400);
      }}
    >
      {({ isSubmitting }) => (
        <Form>
          <label>Name:</label>
          <Field type="text" name="name" />
          <ErrorMessage name="name" component="div" />
          <br />
          <label>Email:</label>
          <Field type="email" name="email" />
          <ErrorMessage name="email" component="div" />
          <br />
          <button type="submit" disabled={isSubmitting}>
            Submit
          </button>
        </Form>
      )}
    </Formik>
  );
}

export default BasicForm;

				
			

Explanation:

  • Formik component: Manages the state of the form.
  • initialValues: Specifies the initial form values.
  • validate function: Contains validation logic. In this case, the form checks whether the fields are filled and if the email is valid.
  • Field component: Automatically links to the form’s state and handles user input.
  • ErrorMessage component: Displays validation errors for individual fields.
  • onSubmit: Handles form submission.

Output:

A simple form that validates the name and email fields. When submitted, the form shows an alert with the entered data.

Handling Validation with Yup

Formik integrates well with Yup, a schema validation library that provides a more structured way to validate form inputs.

To use Yup with Formik, you need to install it:

				
					npm install yup

				
			

Here’s how you can use Yup to validate a form:

				
					import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';

const SignupSchema = Yup.object().shape({
  name: Yup.string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required('Required'),
  email: Yup.string().email('Invalid email').required('Required'),
});

function FormWithYup() {
  return (
    <Formik
      initialValues={{ name: '', email: '' }}
      validationSchema={SignupSchema}
      onSubmit={(values) => {
        alert(JSON.stringify(values, null, 2));
      }}
    >
      <Form>
        <label>Name:</label>
        <Field type="text" name="name" />
        <ErrorMessage name="name" component="div" />
        <br />
        <label>Email:</label>
        <Field type="email" name="email" />
        <ErrorMessage name="email" component="div" />
        <br />
        <button type="submit">Submit</button>
      </Form>
    </Formik>
  );
}

export default FormWithYup;

				
			

Explanation:

  • Yup Schema: A Yup object is created using Yup.object().shape to define validation rules for each field.
  • validationSchema: This property connects Yup validation with Formik.

Output:

This form includes validation for the name and email fields using Yup. The email must follow a proper format, and the name must be between 2 and 50 characters.

Handling Complex Forms with Formik

Complex forms often involve multiple fields, conditional rendering, and multiple validation rules. Let’s explore how Formik can handle more advanced forms.

Example: Multi-Step Form with Formik

				
					import React, { useState } from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';

function MultiStepForm() {
  const [step, setStep] = useState(1);

  const handleNextStep = () => setStep(step + 1);
  const handlePreviousStep = () => setStep(step - 1);

  const StepOneSchema = Yup.object().shape({
    firstName: Yup.string().required('First name is required'),
  });

  const StepTwoSchema = Yup.object().shape({
    email: Yup.string().email('Invalid email').required('Email is required'),
  });

  return (
    <Formik
      initialValues={{ firstName: '', email: '' }}
      validationSchema={step === 1 ? StepOneSchema : StepTwoSchema}
      onSubmit={(values) => {
        alert('Form submitted successfully!');
      }}
    >
      {({ isSubmitting }) => (
        <Form>
          {step === 1 && (
            <>
              <label>First Name:</label>
              <Field type="text" name="firstName" />
              <ErrorMessage name="firstName" component="div" />
              <br />
              <button type="button" onClick={handleNextStep}>
                Next
              </button>
            </>
          )}

          {step === 2 && (
            <>
              <label>Email:</label>
              <Field type="email" name="email" />
              <ErrorMessage name="email" component="div" />
              <br />
              <button type="button" onClick={handlePreviousStep}>
                Back
              </button>
              <button type="submit" disabled={isSubmitting}>
                Submit
              </button>
            </>
          )}
        </Form>
      )}
    </Formik>
  );
}

export default MultiStepForm;

				
			

Explanation:

  • Multi-step forms are handled by conditionally rendering different form sections based on the step state.
  • Each step has its own validation schema using Yup.
  • Buttons allow navigating between steps or submitting the form when all steps are complete.

Output:

A multi-step form where the user fills in their first name in the first step, then moves to the second step to enter their email before submitting the form.

Form Submission and Error Handling in Formik

Handling errors during form submission (e.g., server errors) is crucial in real-world applications. Here’s how to handle submission errors:

				
					import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';

function FormWithErrorHandling() {
  return (
    <Formik
      initialValues={{ email: '' }}
      onSubmit={(values, { setSubmitting, setErrors }) => {
        setTimeout(() => {
          if (values.email === 'test@test.com') {
            setErrors({ email: 'This email is already taken' });
          } else {
            alert('Form submitted successfully');
          }
          setSubmitting(false);
        }, 400);
      }}
    >
      {({ isSubmitting }) => (
        <Form>
          <label>Email:</label>
          <Field type="email" name="email" />
          <ErrorMessage name="email" component="div" />
          <br />
          <button type="submit" disabled={isSubmitting}>
            Submit
          </button>
        </Form>
      )}
    </Formik>
  );
}

export default FormWithErrorHandling;

				
			

Explanation:

  • setErrors is used to display errors for specific fields (e.g., if the email is already in use).
  • isSubmitting tracks whether the form is currently being submitted.

Output:

A form that checks if the email is already taken and displays an error message if it is.

Advanced Techniques with Formik

Dynamic Fields

Dynamic forms can add or remove fields based on user interaction. Formik allows you to handle dynamic fields by updating the form’s state.

Field Arrays in Formik

Formik provides a way to manage arrays of fields (e.g., a form where the user adds multiple phone numbers). You can use Formik’s FieldArray component for this purpose.

Formik is a powerful and flexible form library for React that simplifies form management, validation, error handling, and submission. Whether you're building simple forms or complex multi-step forms, Formik provides all the necessary tools to manage form state efficiently. With features like integration with Yup for schema-based validation, support for dynamic fields, and easy error handling, Formik reduces the boilerplate code associated with forms and enhances the development experience. Happy Coding!❤️

Table of Contents