image_logo_meet

От халепа... Ця сторінка ще не має українського перекладу, але ми вже над цим працюємо!

cookies

Hi! This website uses cookies. By continuing to browse or by clicking “I agree”, you accept this use. For more information, please see our Privacy Policy

bg

Effective forms: form validation with Yup, React Hook Form, and Typescript

author

Ihor Belehai

/

Front End Developer

5 min read

5 min read

And so, we return to our series of articles about building forms with React, Typescript, React Hook Form, Material-UI, and Yup. In the previous article, we got acquainted with React Hook Form and created a basic form. Today, we’ll continue building our form by adding a validation with Yup.

As always, if you want to see the final source code of the series, visit the following link.

You can also play with the demo.

Contents

  1. Getting started
  2. Creating a validation schema
  3. Integrating Yup validation into React Hook Form
  4. Debugging validation with Devtools
  5. Conclusion

Front-end

Getting started

If you want to understand how to smooth out the creation of a form before using Yup, we recommend checking out the previous article. If you are ready to get into the finer details of validation, you’re in the right place. 

Let’s go!

  1. For starters, install the required dependencies:
npm i yup

2. Then, install types as devDependencies to autocomplete support:

npm i -D @types/yup

Creating a validation schema

Let’s refer to the form schema we built in the previous article:

  • title – required, min 2 characters, max 120
  • date – date picker, required, min date is today
  • selected plan – dropdown, one of Premium/Basic, required
  • pet information

name – required, min 2 characters, max 120

breed – required, min 2 characters, max 120

description – optional, min 2 characters, max 500

  • contact information

first name – required, min 2 characters, max 120

last name – required, min 2 characters, max 120

phone number – required, correct phone number format

email – optional, valid email format

call me back – checkbox, true/false

With such requirements, building a validation with Yup takes minimal effort. Let’s have a go:

3. Create a file validation.ts in the root of the project

4. Import Yup:

import * as yup from 'yup';

5. Now, create a Yup object to describe our Appointment validation:

export const validationSchema = yup.object().shape({
  // here we are going to add a validation of each of our fields
});

6. Add validation for each field one by one starting from the title:

// title - required, min 2 characters, max 120
title: yup.string().required().min(2).max(120)

As you see, you can write Yup validation chaining validation rules:

  • yup.string() says that “title” will be a string type
  • required() notes that the “title” required should have a value
  • min(2) says that the value should be at least 2 characters long
  • max(120) requires a maximum of 120 characters long

7. As we go forward, let’s describe the validation for the date field:

const today = new Date();
today.setHours(0, 0, 0, 0); // make it today 00:00:00:00
// date - datepicker, required, min date is today
date: yup.date().min(today).required()
  • yup.date() is used for validating the fields. As long as your value can be passed to a new Date() and return a valid Date object, it can be validated with this method;
  • min(new Date()) says the minimum date is today. You can set any date as a parameter here according to your requirements;
  • You can also set the max() date here.

8. Now let’s take a look at the plan field. The user should choose between two options: Basic and Premium. Let’s make that work:

// selected plan - dropdown, one of Premium/Basic, required
plan: yup
    .string()
    .oneOf([AppointmentPlan.Basic, AppointmentPlan.Premium])
    .required(),
  • oneOf([options]) allows us to specify the exact list of acceptable values.

We’ve successfully described some of our validation rules. At this point, our schema should look like this:

export const validationSchema = yup.object().shape({
  title: yup.string().required().min(2).max(120),
  date: yup.date().min(new Date()).required(),
  plan: yup
    .string()
    .oneOf([AppointmentPlan.Basic, AppointmentPlan.Premium])
    .required(),
});

9. Now, following the previous examples, let’s describe the pet validation:

/* 
	Pet information
  - name - required, min 2 characters, max 120
  - breed - required, min 2 characters, max 120
  - description - optional, min 2 characters, max 500
*/

pet: yup.object({
  name: yup.string().required().min(2).max(120),
  breed: yup.string().required().min(2).max(120),
  description: yup.string().min(2).max(120),
})

If you want to describe an object, use yup.object(). Moreover, if the field is optional, we just don’t use required().

10. Do the same with the contact object validation:

/* 
	Contact information
  - first name - required, min 2 characters, max 120
	- last name - required, min 2 characters, max 120
	- phone number - required, correct phone number format
	- email - optional, correct email format
	- call me back - checkbox, true/false
*/

contact: yup.object({
  firstName: yup.string().required().min(2).max(120),
  lastName: yup.string().required().min(2).max(120),
  callMeBack: yup.boolean().required(),
	email: yup.string().email()
}),

As you see, yup.string() has email() method which allows us to check whether the email has a correct format!

11. The only field left to validate is phoneNumber. We can implement the validation for this field in several ways:

  • You could validate the phone number using matches() and regular expressions:
const phoneRegExp = /^((\\+[1-9]{1,4}[ \\-]*)|(\\([0-9]{2,3}\\)[ \\-]*)|([0-9]{2,4})[ \\-]*)*?[0-9]{3,4}?[ \\-]*[0-9]{3,4}?$/
...
phoneNumber: yup.string().matches(phoneRegExp)

But I’ve given this example just to let you know that it is possible. Meanwhile, I prefer another method:

  1. Install dependencies:
npm i yup-phone

2. Import into the file with validation schema validation.ts:

import 'yup-phone';

3. Apply it:

phoneNumber: yup.string().phone()

I prefer using yup-phone because it utilizes google-libphonenumber (a library that parses, formats, stores, and validates international phone numbers), which gives accurate validation checks. We don’t have to reinvent the wheel for code created before we needed it.


12. Finally, we’ve finished setting up our validation rules. Now your validation.ts file should look like this:

import * as yup from 'yup';
import { AppointmentPlan } from './models';
import 'yup-phone';

export const validationSchema = yup.object().shape({
  title: yup.string().required().min(2).max(120),
  date: yup.date().min(new Date()).required(),
  plan: yup
    .string()
    .oneOf([AppointmentPlan.Basic, AppointmentPlan.Premium])
    .required(),
  contact: yup.object({
    firstName: yup.string().required().min(2).max(120),
    lastName: yup.string().required().min(2).max(120),
    phoneNumber: yup.string().phone(),
    email: yup.string().email(),
    callMeBack: yup.boolean().required(),
  }),
  pet: yup.object({
    name: yup.string().required().min(2).max(120),
    breed: yup.string().required().min(2).max(120),
    description: yup.string().min(2).max(120),
  })
});

Looks great. Now we are ready to move on.

Integrating Yup validation into React Hook Form

Now, it’s time to connect our validation schema with React Hook Form.

  1. Install @hookform/resolvers
npm i @hookform/resolvers

This package contains validation resolvers for React Hook Form. It includes various validation libraries: Yup, Zod, class-validator, and so on.


2. Import yup Resolver into AppointmentForm.TSX along with our brand new validation schema:

import { yupResolver } from '@hookform/resolvers/yup';
import { validationSchema } from '../validation';

3. Use it inside of useForm:

const form: UseFormReturn<Appointment, UseFormProps> = useForm<Appointment>({
  defaultValues,
	// Use yup resolver inside React Hook Form
  resolver: yupResolver(validationSchema)
});

As you can see, that’s quite simple.

Debugging validation with Devtools

You might remember that the previous article discussed a powerful React Hook Form feature — DevTools. Now, we’ll use that to make sure that our validation really works:

  1. Fill the form in with incorrect values. For example:

title – 1 character

date – yesterday

pet name – ‘Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.’ (123 characters)

2. Press the “Make an appointment” button.

3. Check DevTools and see ERROR Type and MESSAGE properties for invalid fields: