Ultimate Guide to Yup Date Validation in React with Formik
Jasser Mark Arioste
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:
- Define the min date
- Create a yup schema specifying the minDate
- Use the yup schema in formik
- 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:
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:
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:
- Wrap a top-level component using
<LocalizationProvider/>
withAdapterDayJS
. - Create a
<FormikMuiDatePicker/>
component to integrate the MUI <DatePicker/> component with Formik. - 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
objects. All 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:
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