DEV Community

John Mark Harrell
John Mark Harrell

Posted on

Beginner's Guide: How to Use Formik!

Form handling in React can be a bit tricky. As applications grow, managing form state, validation, and submission can become cumbersome, especially with complex forms. Enter Formik—a popular library designed to simplify form handling in React. Formik reduces boilerplate code, improves form validation, and helps you manage form state in a clean and scalable way. In this guide, we'll explore how to use Formik in your React applications effectively, from installation to advanced features.

What is Formik?

Formik is a library that helps manage form state, validation, and submission in React applications. It provides utilities for controlling form input values, managing form submission, and handling validation errors. It’s particularly helpful for handling complex forms with many fields, validation requirements, and dynamic behaviors.

Formik was created to solve several issues that come with handling forms manually in React:

  • State management: Keeping track of the form values and the validation state.
  • Validation: Managing validation logic for form fields.
  • Form submission: Handling form submission with minimal boilerplate.

Installing Formik

To start using Formik, you need to install it in your project. If you’re using npm, you can install Formik with the following command:

npm install formik
Enter fullscreen mode Exit fullscreen mode

Alternatively, if you're using yarn:

yarn add formik
Enter fullscreen mode Exit fullscreen mode

Once installed, you can start using Formik in your form components.

Basic Setup

Let’s start with a basic example to demonstrate how Formik works.

import React from 'react';
import { useFormik } from 'formik';

const BasicForm = () => {
    const formik = useFormik({
        initialValues: {
            name: '',
            email: '',
        },
        onSubmit: (values) => {
            alert(JSON.stringify(values, null, 2));
        },
    });

    return (
        <form onSubmit={formik.handleSubmit}>
            <div>
                <label htmlFor="name">Name</label>
                <input
                    id="name"
                    type="text"
                    name="name"
                    onChange={formik.handleChange}
                    value={formik.values.name}
                />
            </div>

            <div>
                <label htmlFor="email">Email</label>
                <input
                    id="email"
                    type="email"
                    name="email"
                    onChange={formik.handleChange}
                    value={formik.values.email}
                />
            </div>

            <button type="submit">Submit</button>
        </form>
    );
};

export default BasicForm;
Enter fullscreen mode Exit fullscreen mode

Explanation:

  1. useFormik Hook: The useFormik hook is the heart of Formik. It returns an object that contains all the form values, validation state, and methods for handling form actions.

  2. initialValues: This object contains the initial values for the form fields. It’s necessary to initialize all fields even if they’re empty at the start.

  3. handleChange: Formik automatically provides a handleChange function, which updates the state of the form whenever a field value changes.

  4. onSubmit: This function is triggered when the form is submitted. The values of the form are passed as a parameter to onSubmit.

Validation with Formik

Form validation is one of the most common requirements when working with forms. Formik makes it easy to manage validation, whether you're performing simple validation rules or integrating a validation library like Yup.

Here’s an example of adding validation to our previous form using Yup:

npm install yup
Enter fullscreen mode Exit fullscreen mode

Once Yup is installed, you can set up validation with Formik:

import React from 'react';
import { useFormik } from 'formik';
import * as Yup from 'yup';

const validationSchema = Yup.object({
    name: Yup.string().required('Name is required'),
    email: Yup.string().email('Invalid email format').required('Email is required'),
});

const ValidatedForm = () => {
    const formik = useFormik({
        initialValues: {
            name: '',
            email: '',
        },
        validationSchema: validationSchema,
        onSubmit: (values) => {
            alert(JSON.stringify(values, null, 2));
        },
    });

    return (
        <form onSubmit={formik.handleSubmit}>
            <div>
                <label htmlFor="name">Name</label>
                <input
                    id="name"
                    type="text"
                    name="name"
                    onChange={formik.handleChange}
                    value={formik.values.name}
                />
                {formik.errors.name && formik.touched.name ? (
                    <div style={{ color: 'red' }}>{formik.errors.name}</div>
                ) : null}
            </div>

            <div>
                <label htmlFor="email">Email</label>
                <input
                    id="email"
                    type="email"
                    name="email"
                    onChange={formik.handleChange}
                    value={formik.values.email}
                />
                {formik.errors.email && formik.touched.email ? (
                    <div style={{ color: 'red' }}>{formik.errors.email}</div>
                ) : null}
            </div>

            <button type="submit">Submit</button>
        </form>
    );
};

export default ValidatedForm;
Enter fullscreen mode Exit fullscreen mode

Explanation of Validation:

  • validationSchema: We define a validation schema using Yup. This schema checks that the name field is required and the email field is both required and in a valid email format.
  • formik.errors: Formik automatically populates this object with any validation errors.
  • formik.touched: This object keeps track of which fields have been visited. It ensures that validation messages are shown only after the field has been interacted with.

Handling Dynamic Forms

Formik also supports handling dynamic fields, such as adding/removing fields based on user input. Let’s say we need to handle multiple phone numbers in a form:

import React, { useState } from 'react';
import { useFormik } from 'formik';

const DynamicForm = () => {
    const [phoneNumbers, setPhoneNumbers] = useState([""]);

    const formik = useFormik({
        initialValues: {
            name: '',
            email: '',
            phoneNumbers: [""],
        },
        onSubmit: (values) => {
            alert(JSON.stringify(values, null, 2));
        },
    });

    const handleAddPhone = () => {
        setPhoneNumbers([...phoneNumbers, ""]);
    };

    const handleRemovePhone = (index) => {
        const updatedPhones = phoneNumbers.filter((_, i) => i !== index);
        setPhoneNumbers(updatedPhones);
    };

    return (
        <form onSubmit={formik.handleSubmit}>
            <div>
                <label htmlFor="name">Name</label>
                <input
                    id="name"
                    type="text"
                    name="name"
                    onChange={formik.handleChange}
                    value={formik.values.name}
                />
            </div>

            <div>
                <label htmlFor="email">Email</label>
                <input
                    id="email"
                    type="email"
                    name="email"
                    onChange={formik.handleChange}
                    value={formik.values.email}
                />
            </div>

            <div>
                <label>Phone Numbers</label>
                {phoneNumbers.map((phone, index) => (
                    <div key={index}>
                        <input
                            type="text"
                            name={`phoneNumbers[${index}]`}
                            value={formik.values.phoneNumbers[index]}
                            onChange={formik.handleChange}
                        />
                        <button type="button" onClick={() => handleRemovePhone(index)}>Remove</button>
                    </div>
                ))}
                <button type="button" onClick={handleAddPhone}>Add Phone</button>
            </div>

            <button type="submit">Submit</button>
        </form>
    );
};

export default DynamicForm;
Enter fullscreen mode Exit fullscreen mode

Key Points:

  • Dynamic Field Management: We use the phoneNumbers array to dynamically add and remove phone number fields.
  • Formik Field Arrays: Formik can manage dynamic form arrays like this, as it binds each input to a specific index in the array.

Conclusion

Formik is an excellent library for managing forms in React applications. Whether you're handling basic forms, implementing complex validations, or working with dynamic fields, Formik simplifies the process and reduces boilerplate code. By using hooks like useFormik and integrating with validation libraries like Yup, you can easily manage form state, handle errors, and submit data without worrying about the underlying mechanics.

Incorporating Formik into your React applications can significantly improve the maintainability and scalability of your form-based UIs. Whether you’re working with simple input fields or building complex forms with conditional logic, Formik is a powerful and flexible tool that integrates seamlessly into React development.

Top comments (0)