File Validation in React with Formik and Yup

olabisi09

Olabisi Olaoye

Posted on August 6, 2023

File Validation in React with Formik and Yup

Dealing with forms in React applications used to be tedious, but with libraries like Formik and Yup, handling form state and validating each field is much easier and efficient. Formik does the overall form management and Yup helps to define the structure and rules to be applied to the form.

When working with file inputs, schema building and validation is not as straightforward as validating a text field, for example. This guide will show how to implement that in a React application.

 

Step 1: Installing Dependencies

To install Formik and Yup, run this on your command line:

npm install formik yup
Enter fullscreen mode Exit fullscreen mode

If you're using yarn, do this instead:

yarn add formik yup
Enter fullscreen mode Exit fullscreen mode

 

Step 2: Handling Form State

The form should consist of a field with an input of type 'file' and a submit button. At this point, the form looks like this:

const MyForm = () => {
  return (
    <form>
      <input type='file' name='myFile' accept='.pdf'/>
      <button type='submit'>Submit Form</button>
    </form>
  )
}

export default MyForm;
Enter fullscreen mode Exit fullscreen mode

There are different ways to handle form state with Formik, but in this guide we'll be using the useFormik hook to directly provide all the Formik helpers needed. Here we can define the initial values of the input field, what happens when the form is submitted, and a validation schema.

import { useFormik } from 'formik';

const MyForm = () => {
  const formik = useFormik({
    initialValues: {
      myFile: ''
    },
    onSubmit: () => {
      console.log('Form submitted!')
    }
  })
  return (
    <form>
      <input type='file' name='myFile' accept='.pdf'/>
      <button type='submit'>Submit Form</button>
    </form>
  )
}

export default MyForm;
Enter fullscreen mode Exit fullscreen mode

 

Step 3: Building the Validation Schema

Next, import Yup into the file to define the set of rules you want the form field to obey. In this guide, we'll be validating the file input in two aspects:

  • The field must be required
  • The file must only accept PDF files
  • The file size must not be more than 3 megabytes

Here's what the validation schema looks like:

import * as Yup from 'yup';

const validationRules = Yup.object().shape({
    myFile: Yup.mixed().required('required')
      .test('fileFormat', 'Only PDF files are allowed', value => {
        if (value) {
          const supportedFormats = ['pdf'];
          return supportedFormats.includes(value.name.split('.').pop());
        }
        return true;
      })
      .test('fileSize', 'File size must be less than 3MB', value => {
        if (value) {
          return value.size <= 3145728;
        }
        return true;
      }),
  })
Enter fullscreen mode Exit fullscreen mode

When validating the file type, we use the test function to determine whether the file extension is .pdf. We also have to test if the file size is not more than 3,145,728 bytes (3 megabytes).

 

Step 4: Displaying Errors in Field

We intend to display the validation errors below the field, so we render a paragraph just below the file input:

<form onSubmit={formik.handleSubmit}>
      <input type='file' name='myFile' accept='.pdf' onChange={handleChange}/>

      <div>{(formik.errors.myFile) ? <p style={{color: 'red'}}>{formik.errors.myFile}</p> : null}</div>
      <br/>
      <button type='submit'>Submit Form</button>
    </form>
Enter fullscreen mode Exit fullscreen mode

To make sure that Formik is actually in charge of the field's state, a function is passed to the input's onChange property. The function sets the value of the field to Formik's state by using the helper function setFieldValue, a function Formik provides to set a field's value to something. It takes two arguments: the name of the field and the value to be set. The onChange function looks like this:

const handleChange = (e) => {
  formik.setFieldValue('myFile', e.target.files[0]);
};
Enter fullscreen mode Exit fullscreen mode

The result of this is that the file is validated every time its value changes and when the form is submitted. Also, Formik's handleSubmit helper function is passed into the form element's onSubmit property. This will trigger Formik's own onSubmit function.

Here's the complete code:

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

const MyForm = () => {
  const validationRules = Yup.object().shape({
    myFile: Yup.mixed().required('required')
      .test('fileFormat', 'Only PDF files are allowed', value => {
        if (value) {
          const supportedFormats = ['pdf'];
          return supportedFormats.includes(value.name.split('.').pop());
        }
        return true;
      })
      .test('fileSize', 'File size must not be more than 3MB', 
      value => {
        if (value) {
          return value.size <= 3145728;
        }
        return true;
      }),
  })

  const formik = useFormik({
    initialValues: {
      myFile: ''
    },
    onSubmit: () => {
      console.log('Submitted')
    },
    validationSchema: validationRules,
  })

  const handleChange = (e) => {
    formik.setFieldValue('myFile', e.target.files[0]);
  };
  return (
    <form onSubmit={formik.handleSubmit}>
      <input type='file' name='myFile' accept='.pdf' onChange={handleChange}/>

      <div>{(formik.errors.myFile) ? <p style={{color: 'red'}}>{formik.errors.myFile}</p> : null}</div>
      <br/>
      <button type='submit'>Submit</button>
    </form>
  )
}

export default MyForm;
Enter fullscreen mode Exit fullscreen mode

That's it! You can check out the code output on Stackblitz here. Thank you for reading, and please let me know of your thoughts about this article.

💖 💪 🙅 🚩
olabisi09
Olabisi Olaoye

Posted on August 6, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related