ReactHustle

Ultimate Guide to Yup Date Validation in React with Formik

Jasser Mark Arioste

Jasser Mark Arioste

Ultimate Guide to Yup Date Validation in React with Formik

Hello hustlers! In this tutorial, you'll learn how to implement date validation in React using Yup and Formik. First, we'll use an ordinary <input/> element then we'll figure out how to implement this on custom UI components like MUI.

Introduction #

Sometimes, we have to implement date validation in our web applications. And sometimes, it's a bit tricky to implement if you don't know what tools to use. In my experience, I've had pretty good success in implementing date validation by using these three libraries: Yup, Formik, dayjs.

What is Yup? #

Yup is a schema validation library for javascript or typescript.  You define a schema for each field that you're trying to validate. This could be an email, name, phone number, string with a minimum length, and even dates. Yup will simplify date validation and save us a ton of time.

What is Formik? #

Formik is a form-state management library in React. Meaning, it tracks all states within a form. It really simplifies form submission and handling, tracking which fields has errors or which fields have been touched, etc.

What is DayJS? #

DayJS is a lightweight l date utility library written in typescript. We'll use this for manipulating the dates and formatting them easily.

Installing the Dependencies #

To begin our date validation implementation, let's first install our three dependencies simultaneously by using the command:

#yarn
yarn add yup formik dayjs

#npm
npm i yup formik dayjs

Now that that's done, Let's go to the examples.

Example  1 - Validating Min Date #

Suppose you're tasked to create a form to schedule a blog post and the scheduled date must be at least two days from now. To implement this, we'll have to specify a min date. 

These are the steps to do this:

  1. Define the min date
  2. Create a yup schema specifying the minDate
  3. Use the yup schema in formik
  4. Display the error message if it doesn't reach the min date

Here's an example component:

// components/SchedulePostForm.tsx
import dayjs from "dayjs";
import { Formik, Form, Field } from "formik";
import { object, date } from "yup";

const SchedulePostForm = () => {
  //1. Define the min date. we format the date to YYYY-MM-DD to exclude the time.
  const minPublishDate = dayjs().add(2, "day").format("YYYY-MM-DD");

  // 2. we create the yup schema inside the component so that the values are accurate.
  const schema = object({
    // 2.1 use the date().min() function to specify the minimum date
    minPublishDate: date().min(
      minPublishDate,
      "Min date must be 2 days from today"
    ),
  });

  return (
    <div>
      {/* 3. use Formik provider */}
      <Formik
        initialValues={{
          // 3.1 set the initial date to two days from now as well
          minPublishDate: minPublishDate,
        }}
        onSubmit={(values) => {
          console.log(values);
        }}
        // 4. integrate the yup schema to this form
        validationSchema={schema}
      >
        {/* use renderProps to get all the states from Formik */}
        {({ errors }) => {
          return (
            // 5. Implement the form
            <Form className="flex flex-col gap-2">
              <div className="form-control w-full max-w-xs">
                <Field
                  type="date"
                  className="input input-bordered"
                  name="minPublishDate"
                />
                {errors.minPublishDate && (
                  <label className="label">
                    <span className="label-text-alt text-error">
                      {errors.minPublishDate}
                    </span>
                  </label>
                )}
              </div>
              <button className="btn btn-primary" type="submit">
                Submit
              </button>
            </Form>
          );
        }}
      </Formik>
    </div>
  );
};
export default SchedulePostForm;

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162

Here's the output if the inputted date is below the min date:

Yup Date Validation React Formik&nbsp;

Example 2 - Validating Max Date #

Suppose you need to create a form that displays an error if a birthdate below 18 years old is inputted. To do this we need to validate the max date.

Here's an example of a react component implementing this behavior:

// components/BirthdayForm.tsx
import dayjs from "dayjs";
import { Formik, Form, Field } from "formik";
import { object, date } from "yup";

const BirthdayForm = () => {
  const eighteen_years_ago = dayjs().subtract(18, "year").format("YYYY-MM-DD");

  const schema = object({
    birthdate: date().max(
      eighteen_years_ago,
      "You must be at least 18 years old to register"
    ),
  });

  return (
    <div>
      <Formik
        initialValues={{
          birthdate: eighteen_years_ago,
        }}
        onSubmit={(values) => {
          console.log(values);
        }}
        validationSchema={schema}
      >
        {({ errors }) => {
          return (
            <Form className="flex flex-col gap-2">
              <div className="form-control w-full max-w-xs">
                <Field
                  type="date"
                  className="input input-bordered"
                  name="birthdate"
                />
                {errors.birthdate && (
                  <label className="label">
                    <span className="label-text-alt text-error">
                      {errors.birthdate}
                    </span>
                  </label>
                )}
              </div>
              <button className="btn btn-primary" type="submit">
                Submit
              </button>
            </Form>
          );
        }}
      </Formik>
    </div>
  );
};

export default BirthdayForm;
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455

It's similar to the first example. The only thing we change is the schema and the max date.

Here's the output. The current date at the time of writing this article is March 22, 2023. If we calculate eighteen years ago, that would be March 22, 2005.

Below, we just went over by one day of the maximum date and it shows us an error message:

Yup Date Validation Max Date

Example 3 - Validation using <DatePicker/> of MUI #

From the previous two examples, we've only been using the native date input. But a very common scenario is to use a <DatePicker/> component from a Custom UI library like MUI. How do we integrate, yup, formik, and dayjs when using MUI?

There are a couple of steps that I recommend:

  1. Wrap a top-level component using <LocalizationProvider/> with AdapterDayJS.
  2. Create a <FormikMuiDatePicker/> component to integrate the MUI <DatePicker/> component with Formik.
  3. Use the <FormikMuiDatePicker/> component in a Formik provider component. 

Step 3-1: Wrapping everything in a LocalizationProvider

Inside your top-level component like <App/> for example, wrap everything in a <LocalizationProvider/>. For example:

import "../styles/globals.css";
import type { AppProps } from "next/app";
import { LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <LocalizationProvider dateAdapter={AdapterDayjs}>
      <Component {...pageProps} />
    </LocalizationProvider>
  );
}

export default MyApp;
1234567891011121314

By using the AdapterDayJS for the dateAdapter we can now directly work with dayjs.Dayjs objectsAll the <DatePicker/> components of MUI can now accept dayjs.Dayjs objects. And in an onChange event, it will pass in this object as well. 

Step 3-2: Integrating MUI DatePicker with Formik

To Integrate MUI DatePicker with Formik, let's create a custom component. First, create the file components/FormikMuiDatePicker.tsx:

// components/MuiDatePicker.tsx
import { DatePicker, DatePickerProps } from "@mui/x-date-pickers";
import { useField, useFormikContext } from "formik";

// Add a name property and reuse the date picker props.
type Props<TDate> = {
  name: string;
} & DatePickerProps<TDate>;

const FormikMuiDatePicker = <TDate,>({ name, ...props }: Props<TDate>) => {
  // use useField hook to get the state values for this field via the name prop.
  const [field, meta] = useField(name);
  const { setFieldValue } = useFormikContext();
  return (
    <div className="form-control w-full max-w-xs">
      <DatePicker
        {...props}
        // use the DatePicker component override the value formik state value
        value={field.value}
        // modify the formik sate using setFieldValue
        onChange={(val) => {
          setFieldValue(name, val);
        }}
      />
      {/* Show an error message if there's any */}
      {meta.error && (
        <label className="label">
          <span className="label-text-alt text-error">{meta.error}</span>
        </label>
      )}
    </div>
  );
};

export default FormikMuiDatePicker;
1234567891011121314151617181920212223242526272829303132333435

Step 3-3: Using the custom date picker

To use our <FormikMuiDatePicker/> component, let's implement a form similar to example #2:

// components/MuiForm.tsx
import dayjs from "dayjs";
import { Formik, Form } from "formik";
import { object, date } from "yup";
import FormikMuiDatePicker from "./FormikMuiDatePicker";

const MuiForm = () => {
  const eighteen_years_ago = dayjs().subtract(18, "year");

  const schema = object({
    birthdate: date().max(
      eighteen_years_ago,
      "You must be at least 18 years old to register"
    ),
  });
  return (
    <div>
      <Formik
        initialValues={{ birthdate: eighteen_years_ago }}
        onSubmit={(values) => {
          console.log(values);
        }}
        validationSchema={schema}
      >
        <Form className="flex flex-col align-strech gap-2">
          {/* here we just need to specify the name */}
          <FormikMuiDatePicker name="birthdate" />
          <button className="btn btn-primary" type="submit">
            Submit
          </button>
        </Form>
      </Formik>
    </div>
  );
};
export default MuiForm;
123456789101112131415161718192021222324252627282930313233343536

Here's a demo:

Yup Date Validation with Formik, MUI and Dayjs

Full Code and Demo #

The full code can be accessed at GitHub: jmarioste/yup-date-validation-formik-tutorial

The demo can be accessed at Stackblitz: Yup Date Validation Formik Tutorial

Conclusion #

We learned how to easily validate dates in React using the combination of three libraries namely Formik, Yup and Dayjs.

Resources #

If you need more information on how to validate dates or other items, please checkout the documentations

Share this post!

Related Posts

Disclaimer

This content may contain links to products, software and services. Please assume all such links are affiliate links which may result in my earning commissions and fees.
As an Amazon Associate, I earn from qualifying purchases. This means that whenever you buy a product on Amazon from a link on our site, we receive a small percentage of its price at no extra cost to you. This helps us continue to provide valuable content and reviews to you. Thank you for your support!
Donate to ReactHustle