React forms with react-hook-form, tailwindcss and Yup for form input validation.
In this tutorial, we will learn how to create a simple user registration form with React, react-hook-form, tailwindcss, and Yup. We will use the useForm hook from react-hook-form to manage the state of the form and to register and validate input fields. We will implement Yup for input validation in the form and use the tailwind css to style the input fields.
- Published on
19 min read
•
Introduction
Forms are a common feature of many web applications, and creating one with the popular React JavaScript library and the react-hook-form
library is a straightforward process. In this tutorial, we'll walk through the steps to create a simple user registration form with three input fields: username, email, and password. We'll use the latest version of react-hook-form (v7.40.0)
and the tailwindcss(v3.0.23)
CSS framework to style our form input fields.
Create project
First, let's create a new React project using the create-react-app
command-line tool:
npx create-react-app my-user-registration-form
Installation
Next, we'll need to install the react-hook-form
and tailwindcss
packages using npm or yarn:
npm install react-hook-form@7.40.0 tailwindcss@3.0.23
or
yarn add react-hook-form@7.40.0 tailwindcss@3.0.23
Implementation
Once the packages are installed, we can import the useForm
hook from react-hook-form
in our UserRegistrationForm.jsx
file:
import { useForm } from 'react-hook-form'
We'll use the useForm
hook to manage the state of our form input fields and to perform input validation.
Next, let's create a UserRegistrationForm component that will render our user registration form. Inside the UserRegistrationForm component, we'll use the useForm hook to initialize the form state and to register our input fields:
const UserRegistrationForm = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm()
return (
<div className="m-auto flex w-1/2 flex-col gap-4">
<h1 className="bold text-2xl underline">Registration Form</h1>
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-2">
<div className="input-wrapper flex flex-col">
<label htmlFor="username">Username</label>
<input
type="text"
{...register('username', {
required: 'Username is required',
minLength: {
value: 3,
message: 'Username must be at least 3 characters',
},
})}
/>
{errors.username && (
<p className="text-xs italic text-red-500">{errors.username.message}</p>
)}
</div>
<div className="input-wrapper flex flex-col">
<label htmlFor="email">Email</label>
<input
type="email"
{...register('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
message: 'Invalid email address',
},
})}
/>
{errors.email && <p className="text-xs italic text-red-500">{errors.email.message}</p>}
</div>
<div className="input-wrapper flex flex-col">
<label htmlFor="password">Password</label>
<input
type="password"
{...register('password', {
required: 'Password is required',
minLength: {
value: 8,
message: 'Password must be at least 8 characters',
},
})}
/>
{errors.password && (
<p className="text-xs italic text-red-500">{errors.password.message}</p>
)}
</div>
</form>
</div>
)
}
export default UserRegistrationForm
We're using the register method provided by the useForm
hook to register each input field. We're also passing in validation rules for each field, which will be enforced when the form is submitted.
If the user enters an invalid value for any of the input fields, the errors object will contain an error message for that field, which we're rendering below each input field.
{
errors.password && <p className="text-xs italic text-red-500">{errors.password.message}</p>
}
Finally, let's add a submit button to our form and handle the form submission in an onSubmit function:
<div className="input-wrapper">
<button
type="submit"
className="focus:shadow-outline rounded bg-blue-500 py-2 px-4 font-bold text-white hover:bg-blue-700 focus:outline-none"
>
Submit
</button>
</div>
const onSubmit = (data) => {
console.log(data)
}
The onSubmit function will be called when the user submits the form, and it will receive the form data as an argument. In this example, we're simply logging the form data to the console, but in a real application, you would likely use this data to create a new user in your database or send it to your server for further processing.
Here's the complete UserRegistrationForm
component:
import React from 'react'
import { useForm } from 'react-hook-form'
const UserRegistrationForm = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm()
// Form submission handler
const onSubmit = (data) => {
// Do something with the form data
}
return (
<div className="m-auto flex w-1/2 flex-col gap-4">
<h1 className="bold text-2xl underline">Registration Form</h1>
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-2">
<div className="input-wrapper flex flex-col">
<label htmlFor="username">Username</label>
<input
type="text"
{...register('username', {
required: 'Username is required',
minLength: {
value: 3,
message: 'Username must be at least 3 characters',
},
})}
/>
{errors.username && (
<p className="text-xs italic text-red-500">{errors.username.message}</p>
)}
</div>
<div className="input-wrapper flex flex-col">
<label htmlFor="email">Email</label>
<input
type="email"
{...register('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
message: 'Invalid email address',
},
})}
/>
{errors.email && <p className="text-xs italic text-red-500">{errors.email.message}</p>}
</div>
<div className="input-wrapper flex flex-col">
<label htmlFor="password">Password</label>
<input
type="password"
{...register('password', {
required: 'Password is required',
minLength: {
value: 8,
message: 'Password must be at least 8 characters',
},
})}
/>
{errors.password && (
<p className="text-xs italic text-red-500">{errors.password.message}</p>
)}
</div>
<div className="input-wrapper">
<button
type="submit"
className="focus:shadow-outline rounded bg-blue-500 py-2 px-4 font-bold text-white hover:bg-blue-700 focus:outline-none"
>
Submit
</button>
</div>
</form>
</div>
)
}
export default UserRegistrationForm
To use the UserRegistrationForm
component in our App
component, we can simply import it and render it in the App
component's render method:
import UserRegistrationForm from './UserRegistrationForm'
function App() {
return (
<div className="App">
<UserRegistrationForm />
</div>
)
}
And that's it! We now have a fully-functioning user registration form with three input fields and input validation using the react-hook-form
and tailwindcss
libraries. You can further customize the form and its input fields by using the various styling options provided by tailwindcss
.
Yup implementation
Another option for input validation in a React form is to use the Yup
package. Yup
is a JavaScript schema builder for value parsing and validation. It can be used with react-hook-form
to provide a simple and straightforward way to validate input fields in a form.
To use Yup
with react-hook-form
, you will first need to install the Yup package:
npm install yup
npm install @hookform/resolvers@2.9.10
or with yarn
yarn add yup
yarn add @hookform/resolvers@2.9.10
Once the package is installed, you can import the object
method from Yup in your UserRegistrationForm
component:
import { object, string } from 'yup'
import { yupResolver } from '@hookform/resolvers/yup'
Next, we'll create a Yup validation schema for our user registration form. The schema will define the rules for each input field and the error messages that should be displayed if the user enters an invalid value for that field: Yupresolver is used to tell the form to use yup schema instead of the builtin methods for validation.
const validationSchema = object().shape({
username: string()
.required('Username is required')
.min(3, 'Username must be at least 3 characters'),
email: string().required('Email is required').email('Invalid email address'),
password: string()
.required('Password is required')
.min(8, 'Password must be at least 8 characters'),
})
We can now use the useForm
hook to initialize the form state and to register our input fields, passing in the validation schema as an option in resolver:
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(validationSchema),
})
Now we can just simply remove the inbuilt validation from the input field.
<input
type="text"
{...register('username', {
required: 'Username is required',
minLength: {
value: 3,
message: 'Username must be at least 3 characters',
},
})}
/>
to
<input type="text" {...register('username')} />
Final UserRegistrationForm
components looks like this:
import React from 'react'
import { useForm } from 'react-hook-form'
import { object, string } from 'yup'
import { yupResolver } from '@hookform/resolvers/yup'
const UserRegistrationForm = () => {
const validationSchema = object().shape({
username: string()
.required('Username is required')
.min(3, 'Username must be at least 3 characters'),
email: string().required('Email is required').email('Invalid email address'),
password: string()
.required('Password is required')
.min(8, 'Password must be at least 8 characters'),
})
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(validationSchema),
})
// Form submission handler
const onSubmit = (data) => {
// Do something with the form data
}
return (
<div className="m-auto flex w-1/2 flex-col gap-4">
<h1 className="bold text-2xl underline">Registration Form</h1>
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-2">
<div className="input-wrapper flex flex-col">
<label htmlFor="username">Username</label>
<input type="text" {...register('username')} />
{errors.username && (
<p className="text-xs italic text-red-500">{errors.username.message}</p>
)}
</div>
<div className="input-wrapper flex flex-col">
<label htmlFor="email">Email</label>
<input type="email" {...register('email')} />
{errors.email && <p className="text-xs italic text-red-500">{errors.email.message}</p>}
</div>
<div className="input-wrapper flex flex-col">
<label htmlFor="password">Password</label>
<input type="password" {...register('password')} />
{errors.password && (
<p className="text-xs italic text-red-500">{errors.password.message}</p>
)}
</div>
<div className="input-wrapper">
<button
type="submit"
className="focus:shadow-outline rounded bg-blue-500 py-2 px-4 font-bold text-white hover:bg-blue-700 focus:outline-none"
>
Submit
</button>
</div>
</form>
</div>
)
}
export default UserRegistrationForm
Using Yup for input validation in a React form is a simple and elegant way to enforce validation rules and display error messages. It provides a declarative and intuitive syntax for defining validation rules, and it integrates seamlessly with react-hook-form.
Screenshots
I hope this tutorial has been helpful in showing you how to create a user registration form with react-hook-form
, tailwindcss
and yup
. Here is the link for the following code : Gist to UserRegistrationForm
Happy coding!