Sabbir Ahmed

Sabbir Ahmed

1 month ago

React Hook Form Tutorial: Simplify React Form Validation with Yup

Working with forms is a regular task for web developers. For simple and less complex forms, we can directly use form in React without needing any library.  But for large and complex applications you might have to use a library to manage the form data and validations. In this article, we will see one of most popular library in React, called React Hook Form and use form validation techniques with another library called Yup. Also see most common uses of validation schemas available. Without further delay, lets start.  


Effortless Form Management with React Hook Form


React Hook Form is one of the most popular libraries available for react to manage form functionalities. There are many reasons because of which this package has got developers' attention. This package comes with very small size and works very fast compared to other libraries. Underneath the hood,  it uses the refs, instead of using states, which makes it able to avoid re-render forms and respond very quickly.  

Installing React hook form is very simple and straight forward. Lets start with installing our react app: 


npx create-react-app my-react-app
cd my-react-app

Now install the react hook form in the project:

    
npm install react-hook-form

Lets say we would have first name and last name of users from a simple form. So in the form component, we will have to add codes like this: 

    
import React from 'react';
import { useForm } from 'react-hook-form';

function App() {
  const { register, handleSubmit, errors } = useForm();
  
  const onSubmit = data => {
    console.log(data);
  };
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input 
        type="text" 
        name="firstName" 
        ref={register({ required: true })} 
        placeholder="First Name" 
      />
      {errors.firstName && <span>This field is required</span>}
      
      <input 
        type="text" 
        name="lastName" 
        ref={register({ required: true })} 
        placeholder="Last Name" 
      />
      {errors.lastName && <span>This field is required</span>}
      
      <button type="submit">Submit</button>
    </form>
  );
}

export default App;

  • Lets have a bit explanation


You can see, there is useForm hook that is provided by the library, it holds all the required states and methods for the form. The register method registers the from inputs with validation rules. If there is a validation failure or error occurs, we can access the error for corresponding input in errors object. Finally the handleSubmit method performs the form submission, which take a function as callback to submit the form and where the submitted form data are provided. 

  • Custom validation


If you want to add custom validations with the inputs, you can pass a extra parameter called validate like this: 



import React from 'react';
import { useForm } from 'react-hook-form';

function App() {
  const { register, handleSubmit, errors } = useForm();
  
  const onSubmit = data => {
    console.log(data);
  };

  const validatePassword = value => {
    // Custom validation logic, for example, password should be at least 8 characters long
    return value.length >= 8 || "Password must be at least 8 characters long";
  };
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input 
        type="password" 
        name="password" 
        ref={register({ required: true, validate: validatePassword })} //custom validation
        placeholder="Password" 
      />
      {errors.password && <span>{errors.password.message}</span>}
      
      <button type="submit">Submit</button>
    </form>
  );
}

export default App;


Here, we are passing a function validatePassword, where we can return a flag (true/false) based on our condition for input value. 

  • Lets run the application


Now you can start the server to check the form submission: 

npm start

Thats how simple it is to integrate react hook form in a react application. But this is just a start, the library comes with a tons of more features. Please have a look to their rich documentation to play with it. 


Form Validation in React: A Guide to Yup with React Hook Form


We now know how to start with React Hook Form. To use validation in here, its very common to use another library called Yup which makes validating your data very simple. 

Lets start with installing the Yup library first: 
 

npm install yup

Lets say we have a registration form to take customer’s first name, last name and email. So we can modify our form component like this: 


import React from 'react';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';

const validationSchema = yup.object().shape({
  firstName: yup.string().required('First name is required'),
  lastName: yup.string().required('Last name is required'),
  email: yup.string().email('Invalid email').required('Email is required'),
});

const MyForm = () => {
  const { register, handleSubmit, errors } = useForm({
    resolver: yupResolver(validationSchema),
  });

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <div>
      <h1>My Form</h1>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div>
          <label>First Name</label>
          <input type="text" name="firstName" ref={register} />
          {errors.firstName && <p>{errors.firstName.message}</p>}
        </div>

        <div>
          <label>Last Name</label>
          <input type="text" name="lastName" ref={register} />
          {errors.lastName && <p>{errors.lastName.message}</p>}
        </div>

        <div>
          <label>Email</label>
          <input type="text" name="email" ref={register} />
          {errors.email && <p>{errors.email.message}</p>}
        </div>

        <div>
          <input type="submit" />
        </div>
      </form>
    </div>
  );
};

export default MyForm;

Here, you can see we are binding the resolver as yupResolver, provided by Yup with useForm hook, from React hook form. It takes a validation schema as an argument, in which we have provided expected validations for each fields based on their name. 

For example, string() validates that the input field should have string value. 

required('First name is required') validates the field cannot be empty, otherwise it will show the custom message given to it’s argument. FYI, You can pass no text as argument, in that case the form will show a default message from library. 

email('Invalid email') checks if the email field is provided with an email or not. 

The handleSubmit method trigger the validations in the from when submitted and if the validations pass, then the onSubmit method triggers 

You can also see, an object errors is provided via useForm hook, where if any validation fails, you can access the error for specific field with it’s input name. So for example, if email field fails to verify, then you can get the message in errors.email.message variable. 

So, thats the most simple example to integrate Yup validation for your react form. 

Yup Validation: Common Yup Schemas for React Hook Form


To work with Yup library, we have to build a validation schema defined for each fields in form. We need to know the grammars how to define these schemas for matching our own requirements. I

  • Common examples of Yup validation schemas


Here are a list of common uses with Yup schemas which you will require when working with different forms: 

1.  Required fields: You can validate required field like this: 


const validationSchema = yup.object().shape({
  firstName: yup.string().required('First name is required'),
  lastName: yup.string().required('Last name is required'),
});

2. Number types: For number type fields you should use number(), also you need to define typeError to validate if user has provided a number value:


    
const validationSchema = yup.object().shape({
  age: yup.number().typeError('Age must be a number').required('Age is required'),
});

3. Email validation: for email type validation, you can use email():


    
const validationSchema = yup.object().shape({
  email: yup.string().email('Invalid email').required('Email is required'),
});

4. Min / Max: for limiting character count from minimum to maximum, you can use min(), or max():


    
const validationSchema = yup.object().shape({
  password: yup.string().min(6, 'Password must be at least 6 characters').max(20, 'Password must be at most 20 characters').required('Password is required'),
});

5. RegExp Validation: Validate input against a regular expression:


    
const validationSchema = yup.object().shape({
  username: yup.string().matches(/^[a-zA-Z0-9_]+$/, 'Invalid username').required('Username is required'),
});

6. Date validation: 


    
const validationSchema = yup.object().shape({
  birthDate: yup.date().max(new Date(), 'Birth date must be in the past').required('Birth date is required'),
});

7. Conditional validation: Sometimes you need to validate fields conditionally in reference to other field’s value. For example, you have a checkbox with name isAdult and age input field and you need to validate, if isAdult is checked, then user should be 18 years or older: 


    
const validationSchema = yup.object().shape({
  isAdult: yup.boolean(),
  age: yup.number().when('isAdult', {
    is: true,
    then: yup.number().min(18, 'Must be at least 18 years old').required('Age is required for adults'),
  }),
});

8. URL Validation: Check if a URL in proper format or not:


    
const validationSchema = yup.object().shape({
  website: yup.string().url('Invalid URL').required('Website URL is required'),
});

9. Array Validation: Validate elements of an array


    
const validationSchema = yup.object().shape({
  tags: yup.array().of(yup.string().required('Tag is required')).min(1, 'At least one tag is required'),
});

10. Phone Number Validation: Validate if input is a valid phone number.


    
const validationSchema = yup.object().shape({
  phoneNumber: yup.string().matches(/^[0-9]{10}$/, 'Invalid phone number').required('Phone number is required'),
});

11. Object Validation: If you need to validate a field as object value which has multiple values in it, you can validate like this: 


    
const validationSchema = yup.object().shape({
  address: yup.object().shape({
    street: yup.string().required('Street is required'),
    city: yup.string().required('City is required'),
    postcode: yup.string().required('Postcode is required'),
  }),
});

12. Custom Validation: You can also do a custom validation where you can write your own logic to validate a field: 


    
const validationSchema = yup.object().shape({
  password: yup.string().test('password-check', 'Password must contain at least one uppercase letter, one lowercase letter, and one number', (value) => {
    return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/.test(value);
  }),
});

13. Array Length Validation: Validate the length of an array.


    
const validationSchema = yup.object().shape({
  items: yup.array().min(2, 'At least two items are required').max(5, 'Maximum of five items allowed'),
});

14. Date Range Validation: Validate if a date falls within a specific range.


    
const validationSchema = yup.object().shape({
  startDate: yup.date().min(new Date(), 'Start date must be in the future').required('Start date is required'),
  endDate: yup.date().min(yup.ref('startDate'), 'End date must be after start date').required('End date is required'),
});

These are generally used schemas you would need repeatedly. But there are plenty more to explore, you can use their documentation for any further requirement. 

So thats all you require to start integrating react hook form in your project. These are the simple steps that will help you with most of the react project and form handling. React hook form is able to handle complex activities, and using Yup with the hook-form makes it very powerful to satisfy most of the requirements. I hope you find this article useful, let me know your thoughts in the comments.

Have a great day. 

Comments

Login As User
Word Count: 0