DEV Community

cmphill
cmphill

Posted on

Using Formik to Create React Forms

Introduction

There's no two ways about it--creating forms in react is a pain. Not to worry: formik includes custom hooks and ready compatibility with yup validations to make creating the form and validating fields a breeze. I will walk you through the process of importing formik, writing forms, and validating fields using yup.

Setup

The first thing that you need to do is navigate to the repository that you want to create a form in. Depending on your package manager preference, run either
npm install formik --save
or
yarn add formik

In the component in which you will be creating the form, include this import line:

  • note that in its simplest form, the only import formik requires is the useFormik hook. If you went this route, you would define your initial values within the hook as well as your validation schema. Unfortunately, this approach requires typing formik all over your form. For this reason, I recommend importing the Formik, Field, Form, and ErrorMessage hooks in your import statement. It will save you a lot of pain later on.

Once you have installed and imported formik, you have the option to install yup to validate your form fields. You can do this by running npm install yup . To ensure that you have all the validations that you need, you can import all in your component with import * as Yup from yup.

Implementation

Once you have the packages installed, it is time to build the form. As with standard react forms, you define a function in the component and set its return to the form fields. Formik requires default values to be defined for each element of the form, similar to the requirement for a default state in a useState hook. The method of validation is also specified (using yup if you imported it) For example, if you were running a haberdashery, you might want a form to add new hats to your collection. Here is some example code of how you might implement that using a formik form:

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

function HatForm({ addHat }) {
  const [errors, setErrors] = useState([]);

  return (
    <Formik
      initialValues={{
        hatName: '',
        hatCost: 0,
        hatStyle: '',
        hatMaterial: '',
      }}
      validationSchema={Yup.object({
        hatName: Yup.string()
          .max(20, 'must be 20 characters or less')
          .required('required'),
        hatCost: Yup.number('must be a number').required('required'),
        hatStyle: Yup.string().max(10, 'must be 10 characters or less'),
        hatMaterial: Yup.string().max(10, 'must be 10 characters or less'),
      })}
      onSubmit={(values) => {
        fetch('http://localhost:5555/hatform', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json', 
          },
          body: JSON.stringify(values),
        })
          .then((res) => {
            if (res.ok) {
              res.json().then((values) => addHat(values));
            } else {
              res.json().then((errors) => {
                console.log(errors);
                setErrors(errors.message);
                console.log(errors);
              });
            }
          });
      }}
    >
      <Form>
        <label htmlFor="hatName"> Hat Name </label>
        <Field name="hatName" type="text" />
        <ErrorMessage name="hatName" />
        <label htmlFor="hatCost"> Hat Cost </label>
        <Field name="hatCost" type="number" />
        <ErrorMessage name="hatCost" />
        <label htmlFor="hatMaterial"> Hat Material </label>
        <Field name="hatMaterial" type="text" />
        <ErrorMessage name="hatMaterial" />
        <button type="submit"> Submit </button>
      </Form>
    </Formik>
  );
}
Enter fullscreen mode Exit fullscreen mode

And that's it! (For your frontend form, at least). You may have noticed that there is an addHat prop in the function declaration. That is because you will likely want to have your hats saved at a higher level in a multi-component website. Once the data has been JSON-ified, it needs to saved in state at the level that suits your project's requirements. As I mentioned earlier, there are different imports that you can import (or not). This is something to be aware of as you begin writing forms in Formik--there are several different ways to write the form that vary in complexity and abstraction. Fortunately, you can view these different approaches right on Formik's Official Website. One of the questions you may have as a new programmer is "why would you include validations on the frontend when the form will be rejected by validations on the backend anyway if the form submission is not within the specifications?" That is a good question, and it fundamentally comes down to user experience. Even if your server returns an error code to the POST request, it may not be visible (or mean much) to your visitor. Frontend validations allow instant feedback to be provided to the user letting them know they need to adjust their input to the field. Another thing to note about handling the errors is that there are several ways to record and display them. You can define an error display element under each form field, or you can have them display as a block that is mapped through at the bottom of your form.

Conclusion

Formik provides a nice upgrade over vanilla react forms. You no longer have to worry about overriding the default behavior of the form submission, and some of the repetitive aspects of typing out forms are no longer required. Depending on how much abstraction you are comfortable with, you can save a great deal of typing. Otherwise, you can use one of the more explicit methods for writing a formik form, and still reap the benefit of easier validations. The choice is up to you.

Top comments (0)