Form Validation in React: Integrating React Hook Form & Yup
Add to your RSS feed20 March 20245 min readTable of Contents
Form validation is a crucial aspect of building robust and user-friendly web applications. In this guide, we'll explore how to integrate React Hook Form (a popular form library for React) with Yup (a schema validation library) to perform efficient form validation in React applications.
What is React Hook Form?
React Hook Form is a lightweight and flexible library for managing form state and performing form validation in React applications. It emphasizes simplicity, performance, and flexibility, making it a popular choice among React developers. In this guide, we'll explore the key features and usage of React Hook Form to build forms efficiently.
React Hook Form simplifies form management, while Yup allows for defining complex validation rules with ease. By following the steps outlined in this tutorial, you can implement efficient and robust form validation in your React projects, ensuring data integrity and a better user experience. Feel free to customize the validation rules and form layout according to your specific requirements.
What is Yup?
Yup is a JavaScript schema validation library that allows you to define validation rules for your data schemas. It's commonly used for form validation in web applications, including with libraries like React Hook Form. Yup provides a declarative way to define validation schemas, making it easy to specify complex validation rules for your data objects. Let's explore the key features and usage of Yup:
Setup the application
Step 1: Install Dependencies
First, make sure you have React, React DOM, React Hook Form, Yup, TypeScript, and TailwindCSS installed in your project:
npx create-react-app react-hook-form-yup --template typescriptthen...
cd react-hook-form-yup && npm install react-hook-form yup @hookform/resolvers
now let's add TailwindCss to our project
npm install -D tailwindcss postcss autoprefixerand
npx tailwindcss init -pIt will generate a "tailwind.config.js" and "postcss.config.js" files in the root folder. Rewrite the tailwind.config.js with this code:
1 /** @type {import('tailwindcss').Config} */2 module.exports = {3 content: [4 './app/**/*.{js,ts,jsx,tsx,mdx}',5 './pages/**/*.{js,ts,jsx,tsx,mdx}',6 './components/**/*.{js,ts,jsx,tsx,mdx}',7 './**/*.{js,ts,jsx,tsx,mdx}',89 // Or if using `src` directory:10 './src/**/*.{js,ts,jsx,tsx,mdx}',11 ],12 theme: {13 extend: {},14 },15 plugins: [],16 };
Step 2: Create a Form Component
Create a new TypeScript file for your form component, for example RegForm.tsx:
1 import { yupResolver } from '@hookform/resolvers/yup';2 import { useForm } from 'react-hook-form';3 import { IRegForm } from './RegForm.props';4 import { userSchema } from './schema';56 const RegForm = () => {7 const {8 register,9 handleSubmit,10 reset,11 formState: { errors },12 } = useForm <13 IRegForm >14 {15 resolver: yupResolver(userSchema),16 };17 const submitForm = (data: IRegForm) => {18 console.log({ data });19 reset();20 };21 console.log(errors);22 return (23 <form className='max-w-sm mx-auto' onSubmit={handleSubmit(submitForm)}>24 <div className='mb-5'>25 <label className='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>26 username27 </label>28 <input29 {...register('username')}30 type='text'31 className='shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 dark:shadow-sm-light'32 placeholder='your username'33 required34 />35 {errors?.username && <span className='text-red-500'>This field is required</span>}36 </div>37 <div className='mb-5'>38 <label className='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>39 email40 </label>41 <input42 {...register('email')}43 type='email'44 className='shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 dark:shadow-sm-light'45 placeholder='email'46 required47 />48 {errors?.email && <span className='text-red-500'>This field is required</span>}49 </div>50 <div className='mb-5'>51 <label className='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>52 phone (123-456-7890)53 </label>54 <input55 {...register('phone')}56 type='tel'57 pattern='[0-9]{3}-[0-9]{3}-[0-9]{4}'58 name='phone'59 className='shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 dark:shadow-sm-light'60 placeholder=' '61 required62 />63 {errors?.phone && <span className='text-red-500'>This field is required</span>}64 </div>65 <div className='mb-5'>66 <label className='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>67 password68 </label>69 <input70 type='password'71 {...register('password')}72 className='shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 dark:shadow-sm-light'73 required74 />75 {errors?.password && <span className='text-red-500'>This field is required</span>}76 </div>77 <div className='mb-5'>78 <label className='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>79 Repeat password80 </label>81 <input82 type='password'83 className='shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 dark:shadow-sm-light'84 required85 />86 </div>87 <div className='flex items-start mb-5'>88 <div className='flex items-center h-5'>89 <input90 id='terms'91 type='checkbox'92 value=''93 className='w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-blue-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800'94 required95 />96 </div>97 <label98 htmlFor='terms'99 className='ms-2 text-sm font-medium text-gray-900 dark:text-gray-300'100 >101 I agree with the{' '}102 <a href='!#' className='text-blue-600 hover:underline dark:text-blue-500'>103 terms and conditions104 </a>105 </label>106 </div>107 <button108 type='submit'109 className='text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800'110 >111 Register new account112 </button>113 </form>114 );115 };116 export default RegForm;
Now, you can use the RegForm component in your main App component or any other component in your application:
1 import RegForm from './components/reg-form/RegForm';23 function App() {4 return (5 <div>6 <RegForm />7 </div>8 );9 }1011 export default App;
Step 3: Create a Props File for Form Component
RegForm.props.ts
1 import { DetailedHTMLProps, FormHTMLAttributes } from 'react';23 export interface IRegForm {4 username?: string;5 email?: string;6 phone?: string;7 password?: string;8 }910 export interface RegFormProps11 extends DetailedHTMLProps<FormHTMLAttributes<HTMLFormElement>, HTMLFormElement> {12 username: string;13 email: string;14 phone?: string;15 password: string;16 }
Step 4: Create a Schema
Create a new TypeScript file for schema, for example schema.ts:
1 import { InferType, ObjectSchema, date, object, string } from 'yup';2 import { IRegForm } from './RegForm.props';34 const regexPhone: RegExp = new RegExp(/\(?([0-9]{3})\)?([ .-]?)([0-9]{3})\2([0-9]{4})/);56 export const userSchema: ObjectSchema<IRegForm> = object({7 username: string().trim().required('Username is required'),8 email: string().email('Email is required'),9 password: string().min(6).max(11).required('Password is required'),10 phone: string().required().matches(regexPhone, 'Wrong phone number format'),11 createdOn: date().default(() => new Date()),12 });1314 export type User = InferType<typeof userSchema>;
Step 5: Running the Application
Ensure your TypeScript compiler is configured properly (e.g., tsconfig.json). Then, start your React application:
npm run startConclusion:
By combining React Hook Form, Yup, and TypeScript, you can create powerful and type-safe forms in your React applications. React Hook Form simplifies form management, Yup provides robust validation capabilities, and TypeScript ensures type safety throughout your application. This approach allows you to build forms with confidence, knowing that your data is validated and your code is free of type errors.