import React from "react"
import { useForm } from "react-hook-form"
import { ErrorMessage } from "@hookform/error-message"
interface FormInputs {
multipleErrorInput: string
}
export default function App() {
const {
register,
formState: { errors },
handleSubmit,
} = useForm<FormInputs>({
criteriaMode: "all",
})
const onSubmit = (data: FormInputs) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register("multipleErrorInput", {
required: "This is required.",
pattern: {
value: /d+/,
message: "This input is number only.",
},
maxLength: {
value: 10,
message: "This input exceed maxLength.",
},
})}
/>
<ErrorMessage
errors={errors}
name="multipleErrorInput"
render={({ messages }) =>
messages &&
Object.entries(messages).map(([type, message]) => (
<p key={type}>{message}</p>
))
}
/>
<input type="submit" />
</form>
)
}
I’m having a hard time figuring out how to handle errors that don’t necessarily pertain to a single input field in a react-hook-form
.
To put it differently, how do I handle handleSubmit
errors?
For example, having the following form:
import to from 'await-to-js'
import axios, { AxiosResponse } from 'axios'
import React from "react"
import { useForm } from "react-hook-form"
type LoginFormData = {
username: string,
password: string,
}
export const Login: React.FC = () => {
const { register, handleSubmit } = useForm<LoginFormData>()
const onSubmit = handleSubmit(async (data) => {
const url = '/auth/local'
const [err, userLoginResult] = await to<AxiosResponse>(axios.post(url, data))
if (userLoginResult) {
alert('Login successful')
}
else if (err) {
alert('Bad username or password')
}
})
return (
<div className="RegisterOrLogIn">
<form onSubmit={onSubmit}>
<div>
<label htmlFor="username">username</label>
<input name="username" id="username" ref={register} />
</div>
<div>
<label htmlFor="password">Password</label>
<input type="password" id="password" name="password" ref={register} />
</div>
<button type="submit"> </button>
</form>
</div>
)
}
Is there a react-hook-form
way of informing the user that there’s an error with either the username or the password?
as in, other than alert()
Perhaps this is answered elsewhere, but I could not find it.
Clarification
The error received from the server does not pertain to a single field:
{
"statusCode": 400,
"error": "Bad Request",
"message": [
{
"messages": [
{
"id": "Auth.form.error.invalid",
"message": "Identifier or password invalid."
}
]
}
],
"data": [
{
"messages": [
{
"id": "Auth.form.error.invalid",
"message": "Identifier or password invalid."
}
]
}
]
}
asked Oct 21, 2020 at 18:48
Joey BaruchJoey Baruch
4,2306 gold badges34 silver badges48 bronze badges
In order to display the error from the server to your user, you need to use:
setError
to set the error programmatically when the server returns an error response.errors
to get the error state of every fields in your form to display to the user.
type FormInputs = {
username: string;
};
const { setError, formState: { errors } } = useForm<FormInputs>();
In your handleSubmit
callback
axios
.post(url, data)
.then((response) => {
alert("Login successful");
})
.catch((e) => {
const errors = e.response.data;
if (errors.username) {
setError('username', {
type: "server",
message: 'Something went wrong with username',
});
}
if (errors.password) {
setError('password', {
type: "server",
message: 'Something went wrong with password',
});
}
});
In your component
<label htmlFor="username">username</label>
<input id="username" {...register("username")} />
<div>{errors.username && errors.username.message}</div>
Live Demo
answered Oct 22, 2020 at 9:07
NearHuscarlNearHuscarl
67.7k18 gold badges266 silver badges232 bronze badges
1
Inspired by @NearHuscarl’s answer, I’ve done the following hack s.t. changes in either the username
or the password
inputs will remove the single error.
This hack does not scale well if your error is related to multiple fields in the form, but it worked for the login use case.
onSubmit:
const onSubmit = handleSubmit(async (data) => {
const url = '/auth/local'
const [err, userLoginResult] = await to<AxiosResponse>(axios.post(url, data)) // see await-to-js
if (userLoginResult) {
alert('Login successful')
}
else if (err) {
const formError = { type: "server", message: "Username or Password Incorrect" }
// set same error in both:
setError('password', formError)
setError('username', formError)
}
})
component:
return (
<div className="RegisterOrLogIn">
<form onSubmit={onSubmit}>
<div>
<label htmlFor="username">username</label>
<input name="username" id="username" ref={register} />
</div>
<div>
<label htmlFor="password">Password</label>
<input type="password" id="password" name="password" ref={register} />
</div>
<div>{errors.username && errors.password?.message /*note the cross check*/}</div>
<button type="submit"> </button>
</form>
</div>
)
by setting and rendering the error on both errors.password
& errors.username
, the error will disappear when the user updates either of those fields.
answered Oct 22, 2020 at 19:40
Joey BaruchJoey Baruch
4,2306 gold badges34 silver badges48 bronze badges
2
Since v7.43.0, you can use the syntax root.xxx
error to handle server error or some global level error.
const onSubmit = () => {
try {
fetch(...)
if (response.statusCode > 300) {
setError('root.serverError', {
type: response.statusCode,
message: e.message,
// meta: {}, // something to be consider to included in the phase 2 with meta object
})
}
} catch(e) {
setError('root.serverCatch', {
type: 'server',
message: e.message
})
}
}
const onClick = () => {
setError('root.random', {
type: 'random',
message: 'random'
})
}
return (
<>
{errors.root.serverError.type === 400 && <p>server response message</p>}
<p>{errors.root.serverError.message}</p>
{errors.root.serverCatch.type === 'server' && <p>server error message</p>}
<p>{errors.root.serverCatch.message}</p>
<p>{errors.root.random.message}</p>
</>
)
RFC
answered Jul 25 at 10:49
pom421pom421
1,74119 silver badges38 bronze badges
According to documentation of react-hook-form I can use name of input element like this «xxx.yyy» and this will result in my prepared data to be
{ xxx: { yyy: value }}
But when I try to use this feature with ‘errors’ I cannot use it. i.e. I cannot write below:
{errors.xxx.yyy && <span>This field is required</span>}
because I get «Cannot read property ‘yyy’ of undefined».
Documentation says that I should use this chaining operator, ?. , so I try it:
{errors?.xxx?.yyy && <span>This field is required</span>}
But nothing displays on the page if required input is omitted. I can see that the mechanism blocks form from being submitted until I write something in this field, that is OK, but why I don’t get the error message on the page?
Bill
17.9k19 gold badges84 silver badges132 bronze badges
asked Dec 23, 2019 at 12:40
it really depend which version you are using.
V3: flat error object
errors['xxx.yyyy']
V4: Nested errors object with better type support
errors?.xxx?.yyyy
we have also build a ErrorMessage
component which you may find it useful.
https://react-hook-form.com/api#ErrorMessage
answered Dec 31, 2019 at 5:04
BillBill
17.9k19 gold badges84 silver badges132 bronze badges
Ok, I found answer myself. I should use this form:
{errors[‘xxx.yyy’] && This field is required}
Then everything works
answered Dec 23, 2019 at 13:00
YotKayYotKay
1,1271 gold badge9 silver badges25 bronze badges
you don’t want to spend your coding time. you can use @hookform/error-message
instead of code manually. it’s very easy. it’ll manage those errors.
just pass the errors object given by react-hook-form and pass the property name that you want to display the error message.
<ErrorMessage errors={errors} name="xxx.yyy" message="This is required" />
OR
if you want to customize your message as you want, you can render
as you want like below.
think that you want to bold and show invalid with red custom css class. then you can render as you want.
<ErrorMessage render={({message}) => <div className="invalid-feedback d-block"><b> {message} </b></div>} errors={errors} name="xxx.yyy"/>
NPM https://www.npmjs.com/package/@hookform/error-message
answered Dec 31, 2020 at 11:47
MafeiMafei
3,1313 gold badges15 silver badges37 bronze badges
Performant, flexible and extensible forms with easy to use validation.
Goal
A simple component to render associated input’s error message.
Install
$ npm install @hookform/error-message
Quickstart
- Single Error Message
import React from 'react'; import { useForm } from 'react-hook-form'; import { ErrorMessage } from '@hookform/error-message'; export default function App() { const { register, formState: { errors }, handleSubmit } = useForm(); const onSubmit = (data) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="singleErrorInput" ref={register({ required: 'This is required.' })} /> <ErrorMessage errors={errors} name="singleErrorInput" /> <ErrorMessage errors={errors} name="singleErrorInput" render={({ message }) => <p>{message}</p>} /> <input name="name" ref={register({ required: true })} /> <ErrorMessage errors={errors} name="name" message="This is required" /> <input type="submit" /> </form> ); }
- Multiple Error Messages
import React from 'react'; import { useForm } from 'react-hook-form'; import { ErrorMessage } from '@hookform/error-message'; export default function App() { const { register, formState: { errors }, handleSubmit } = useForm({ criteriaMode: 'all', }); const onSubmit = (data) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input name="multipleErrorInput" ref={register({ required: 'This is required.', pattern: { value: /d+/, message: 'This input is number only.', }, maxLength: { value: 10, message: 'This input exceed maxLength.', }, })} /> <ErrorMessage errors={errors} name="multipleErrorInput" render={({ messages }) => messages && Object.entries(messages).map(([type, message]) => ( <p key={type}>{message}</p> )) } /> <input type="submit" /> </form> ); }
API
Prop | Type | Required | Description |
---|---|---|---|
name |
string |
✓ | Associated field name. |
errors |
object |
errors object from React Hook Form. It’s optional if you are using FormProvider . |
|
message |
string | React.ReactElement |
inline error message. | |
as |
string | React.ReactElement | React.ComponentType |
Wrapper component or HTML tag. eg: as="p" , as={<p />} or as={CustomComponent} . This prop is incompatible with prop render and will take precedence over it. |
|
render |
Function |
This is a render prop for rendering error message or messages. Note: you need to set criteriaMode to all for using messages. |
Backers
Thank goes to all our backers! [Become a backer].
Contributors
Thanks goes to these wonderful people. [Become a contributor].
As a React developer, you must know how to implement validation in form, and a form may hold one or more than one input element.
If you want to get the user-provided data in a subtle manner, then you must show reverence to proper error handling.
In this tutorial, we would like to show you how to add validation in React, show appropriate error messages in React application using Hook Form and Yup packages.
Let us understand what error messages are and why they should be displayed to the user.
Seldom, a user enters incorrect values into the form fields, and you must have seen some error messages manifest on the screen. These messages help in hinting your users about their blunders.
As per the common notion, error messages play a vital role in such a scenario and help users easily determine the issue. After that, users can quickly fix it and submit the form with absolutely no error.
How to Use React Hook Form to Show Validation Error Messages
- Step 1: Set Up React Project
- Step 2: Add Bootstrap Library
- Step 2: Add Yup and Hook Form Plugins
- Step 3: Create Form Component File
- Step 4: List Form Module in App Js
- Step 5: Run Development Server
Set Up React Project
First step tells you how to deal with blank React project installation.
On the terminal screen, you have to type the given command and quickly execute it.
npx create-react-app react-shine
Carefully enter into the project folder.
cd react-shine
Add Bootstrap Library
This instruction is for adding the bootstrap in React app. Now, you have to add the library so run the following command.
npm install bootstrap
Here, you have to include and use the bootstrap UI component in React. Ensure that you are importing the bootstrap CSS path in App.js file.
import React from 'react'
import 'bootstrap/dist/css/bootstrap.min.css'
export default function App() {
return (
<>
<>
)
}
Add Yup and Hook Form Plugins
Let us install the yup and hook form plugins, you have to use the provided command to add the libraries.
npm install @hookform/resolvers yup
Create Form Component File
We are going to build a new component, this file will have the code to show error messages.
Therefore, open the component/ folder and make a new file inside the folder. You can name it ErrorMsg.js file.
import React from 'react'
import * as Yup from 'yup'
import { yupResolver } from '@hookform/resolvers/yup'
import { useForm } from 'react-hook-form'
export default function ErrorMsg() {
const yupValidation = Yup.object().shape({
name: Yup.string()
.required('Please enter some value.')
.min(4, 'Add minimum 4 characters'),
email: Yup.string().required('Email id is mendatory').email(),
})
const formOptions = { resolver: yupResolver(yupValidation) }
const { register, handleSubmit, reset, formState } = useForm(formOptions)
const { errors } = formState
function onSubmit(data) {
console.log(JSON.stringify(data, null, 4))
return false
}
return (
<div className="container mt-4">
<h2>React Integrate Validation Error Messages with Hook Form</h2>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="form-group">
<label>Name</label>
<input
name="name"
type="text"
className={`form-control ${errors.name ? 'is-invalid' : ''}`}
{...register('name')}
/>
<div className="invalid-feedback">{errors.name?.message}</div>
</div>
<div className="form-group">
<label>Email</label>
<input
name="email"
type="text"
className={`form-control ${errors.email ? 'is-invalid' : ''}`}
{...register('email')}
/>
<div className="invalid-feedback">{errors.email?.message}</div>
</div>
<div className="mt-3">
<button type="submit" className="btn btn-primary">
Send
</button>
</div>
</form>
</div>
)
}
List Form Module in App Js
This instruction is all about listing the error message component in React’s main app component file.
Hence, open the src/App.js and import the component as shown below.
import React from 'react'
import ErrorMsg from './components/ErrorMsg'
import 'bootstrap/dist/css/bootstrap.min.css';
export default function App() {
return (
<div className="App">
<ErrorMsg />
</div>
)
}
Run Development Server
Lastly, you have to open the terminal again type the command and press enter.
npm start
Here is the url that you can use to check the app on the browser.
http://localhost:3000
Conclusion
We built a simple form with only two input controls name and email. And learned how to set validation error messages in React app using hook form and yup libraries.
Not just that, we also determine how to set form from the absolute beginning.