JavaScript Development Space

Form Validation in React: Integrating React Hook Form & Yup

Add to your RSS feed20 March 20245 min read
Form Validation in React: Integrating React Hook Form & Yup

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 typescript

then...

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 autoprefixer

and

npx tailwindcss init -p

It will generate a "tailwind.config.js" and "postcss.config.js" files in the root folder. Rewrite the tailwind.config.js with this code:

js
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}',
8
9 // 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:

js
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';
5
6 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 username
27 </label>
28 <input
29 {...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 required
34 />
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 email
40 </label>
41 <input
42 {...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 required
47 />
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 <input
55 {...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 required
62 />
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 password
68 </label>
69 <input
70 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 required
74 />
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 password
80 </label>
81 <input
82 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 required
85 />
86 </div>
87 <div className='flex items-start mb-5'>
88 <div className='flex items-center h-5'>
89 <input
90 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 required
95 />
96 </div>
97 <label
98 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 conditions
104 </a>
105 </label>
106 </div>
107 <button
108 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 account
112 </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:

js
1 import RegForm from './components/reg-form/RegForm';
2
3 function App() {
4 return (
5 <div>
6 <RegForm />
7 </div>
8 );
9 }
10
11 export default App;

Step 3: Create a Props File for Form Component

RegForm.props.ts

js
1 import { DetailedHTMLProps, FormHTMLAttributes } from 'react';
2
3 export interface IRegForm {
4 username?: string;
5 email?: string;
6 phone?: string;
7 password?: string;
8 }
9
10 export interface RegFormProps
11 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:

js
1 import { InferType, ObjectSchema, date, object, string } from 'yup';
2 import { IRegForm } from './RegForm.props';
3
4 const regexPhone: RegExp = new RegExp(/\(?([0-9]{3})\)?([ .-]?)([0-9]{3})\2([0-9]{4})/);
5
6 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 });
13
14 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 start

React rating component React Hook Form + Yup

Conclusion:

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.

JavaScript Development SpaceJavaScript Development Space is your hub for mastering JavaScript and keeping up with the latest in web development. From beginner tutorials to advanced techniques, we offer expert guidance, practical tips, and powerful tools to help you elevate your coding skills. Join our community to explore innovative solutions, tackle real-world projects, and stay ahead of the curve with the newest trends in JavaScript.

© 2024 JavaScript Development Space - Master JS and NodeJS. All rights reserved.