I am Using react-Hook-form, I have a scenario for a phone number that has three Input Field XXX-XXX-XXXX. I want to shift focus from the first input to the next after it reaches maxlength===3.please suggest a solution to auto Focus on the next phone input after reaches max length. working on react functional component.
Here is the code,
import React from 'react';
import { useForm } from "react-hook-form";
export function PhoneInput(props) {
const {
register,
handleSubmit,
watch,
clearErrors,
formState: { errors }
} = useForm();
return (
<form className="review-your-info-form" id="purchase-form" onSubmit={handleSubmit(onSubmit)} noValidate>
<div className="field">
{ (errors.phone1 || errors.phone2 || errors.phone3) && <div className="error-msg"><span className="required">{errors.phone1?.message || errors.phone2?.message || errors.phone3?.message}</span></div>}
<label htmlFor="phone1">Phone *</label>
<div className="phone-group flex">
<input
id="phone1"
type="tel"
className="phone1"
maxLength="3"
onClick={() => clearErrors("phone1")}
{...register("phone1",{
required: 'phone-error',
minLength: {
value: 3,
message: 'phone-error'
},
pattern: {
value: /[2-9][0-9]{2}$/,
message: 'phone-error'
},
})}
/>
<input
type="tel"
className="phone2"
maxLength="3"
onClick={() => clearErrors("phone2")}
{...register("phone2",{
required: 'phone-error',
minLength: {
value: 3,
message: 'phone-error'
},
pattern: {
value: /[2-9][0-9]{2}$/,
message: 'phone-error'
},
})}
/>
<input
type="tel"
className="phone3"
maxLength="4"
onClick={() => clearErrors("phone3")}
{...register("phone3",{
required: 'phone-error',
minLength: {
value: 4,
message: 'phone-error'
},
pattern: {
value: /^[0-9]*$/i,
message: 'phone-error'
},
})}
/>
</div>
</div>
</form>
)}```
To move focus in React you could use useRef hook:
import React, { useState, useRef } from 'react';
import { useForm } from "react-hook-form";
export function PhoneInput(props) {
const [input, setInput] = useState();
const {
register,
handleSubmit,
watch,
clearErrors,
formState: { errors }
} = useForm();
const inputToFocus = useRef(); //<-- create ref
const handleChange = (e) => {
setInput(e.target.value);
if (e.target.value.length >= 3) inputToFocus.current.focus(); //<--- focus second input
}
return (
<form className="review-your-info-form" id="purchase-form" onSubmit={handleSubmit(onSubmit)} noValidate>
<div className="field">
{ (errors.phone1 || errors.phone2 || errors.phone3) && <div className="error-msg"><span className="required">{errors.phone1?.message || errors.phone2?.message || errors.phone3?.message}</span></div>}
<label htmlFor="phone1">Phone *</label>
<div className="phone-group flex">
<input
value={input}
onChange={handleChange} //<-- edit input
id="phone1"
type="tel"
className="phone1"
maxLength="3"
onClick={() => clearErrors("phone1")}
{...register("phone1",{
required: 'phone-error',
minLength: {
value: 3,
message: 'phone-error'
},
pattern: {
value: /[2-9][0-9]{2}$/,
message: 'phone-error'
},
})}
/>
<input
ref={inputToFocus} //<-- assing ref
type="tel"
className="phone2"
maxLength="3"
onClick={() => clearErrors("phone2")}
{...register("phone2",{
required: 'phone-error',
minLength: {
value: 3,
message: 'phone-error'
},
pattern: {
value: /[2-9][0-9]{2}$/,
message: 'phone-error'
},
})}
/>
<input
type="tel"
className="phone3"
maxLength="4"
onClick={() => clearErrors("phone3")}
{...register("phone3",{
required: 'phone-error',
minLength: {
value: 4,
message: 'phone-error'
},
pattern: {
value: /^[0-9]*$/i,
message: 'phone-error'
},
})}
/>
</div>
</div>
</form>
)}
Explanation: the first input has to pass the focus to the second input when value reach length of 3 so:
I create a inputToFocus ref and assign to the second input;
then I create handleChange function to: set the first input value and, in case of value length >= 3, move the focus to second input using ref previously created.
Related
Currently I am using semantic ui css multiple dropdown validation. How do I validate the dropdown so that user has to choose at least ONE option before submitting ?
Right now the current output is that if I submit the form WITHOUT choosing any option, the error message appears.
However, if I choose an option and the submit, the error message still appears.
Following is my code.
import React, { useState } from 'react'
import { Button, Checkbox, Form, Dropdown } from 'semantic-ui-react'
//validation dependencies
import { useForm, Controller } from "react-hook-form";
import { yupResolver } from '#hookform/resolvers/yup';
import * as Yup from 'yup';
function TestForm() {
const validationSchema = Yup.object().shape({
firstName: Yup.string()
.required('firstName is required')
.min(6, 'firstName must be at least 6 characters')
,
options: Yup
.object()
.shape({
key: Yup.number().required("key is required (from label)"),
value: Yup.string().required("Value is required")
})
.nullable() // for handling null value when clearing options via clicking "x"
.required("options is required (from outter null check)")
});
const formOptions = { mode: 'all', reValidateMode: 'onChange', resolver: yupResolver(validationSchema) };
const { register, handleSubmit, reset, formState: { errors }, watch, setValue, control } = useForm(formOptions);
const [stateOptions, setStateOptions] = useState([
{
key: 1,
text: 'aaaa',
value: 'a'
},
{
key: 2,
text: 'bbbb',
value: 'b'
},
{
key: 3,
text: 'cccc',
value: 'c'
},
]);
console.log(watch())//For Debugging
const onSubmitHandler = (data) => {
console.log({ data });
setValue('firstName', 'dash', { shouldDirty: true, shouldValidate: true })
}
return (
<div>
<Form reply onSubmit={handleSubmit(onSubmitHandler)}>
<Form.Field>
<label>First Name</label>
<input placeholder='First Name' name="firstName" {...register('firstName')} />
<div className="invalid-feedback">{errors.firstName?.message}</div>
</Form.Field>
<Form.Field>
<Controller
name="options"
control={control}
render={({ field }) => (
<Dropdown
{...field}
placeholder='State'
fluid
multiple
search
selection
options={stateOptions}
/>
)}
/>
<div className="invalid-feedback">{errors.options?.message || errors.options?.value.message}</div>
</Form.Field>
<Form.Field>
<Button type='submit'>Submit</Button>
</Form.Field>
</Form>
</div>
)
}
export default TestForm
Since Dropdown component in semantic-ui-react doesn't support ref attribute, so you need to controll the value of DropDown by yourself, here is an example you can try on it:
const options = [
{
key: 1,
text: 'aaaa',
value: 'a',
},
{
key: 2,
text: 'bbbb',
value: 'b',
},
{
key: 3,
text: 'cccc',
value: 'c',
},
]
function TestForm() {
const validationSchema = Yup.object().shape({
firstName: Yup.string()
.required('firstName is required')
.min(6, 'firstName must be at least 6 characters'),
options: Yup.array()
.of(Yup.object()
.shape({
key: Yup.number().required('key is required (from label)'),
value: Yup.string().required('Value is required'),
}))
.test(
"required",
"options is required",
(value) => Array.isArray(value) && value.length > 0
),
});
const formOptions = {
mode: 'all',
reValidateMode: 'onChange',
resolver: yupResolver(validationSchema),
};
const {
register,
handleSubmit,
formState: { errors },
setValue,
control,
} = useForm(formOptions);
const onSubmitHandler = (data) => {
console.log(data);
};
return (
<div>
<Form reply onSubmit={handleSubmit(onSubmitHandler)}>
<Form.Field>
<label>First Name</label>
<input
placeholder="First Name"
name="firstName"
{...register('firstName')}
/>
<div className="invalid-feedback">{errors.firstName?.message}</div>
</Form.Field>
<Form.Field>
<Controller
name="options"
control={control}
render={({ field }) => {
let { value, ...other } = field;
return (
<Dropdown
{...other}
placeholder="State"
fluid
multiple
search
selection
options={options}
value={Array.isArray(value) ? value.map(v => v.value) : []}
onChange={(e,{value})=> {
const values = value.map(v => options.find(item => item.value == v));
setValue('options', values)
}}
/>
);
}}
/>
<div className="invalid-feedback">
{errors.options?.message || errors.options?.value.message}
</div>
</Form.Field>
<Form.Field>
<Button type="submit">Submit</Button>
</Form.Field>
</Form>
</div>
);
}
How to add validation, I want show error message on for phone number field (helperText, min 10 , max 10 ) and also show error message if submitted without 10 numeric digit
import ReactPhoneInput from "react-phone-input-2"
import {TextField,Button}from "#material-ui/core"
const {register, handleSubmit,formState: { errors }} = useForm()
const getData= (data) => {
console.log(data.username)
console.log(data.phone);
}
<form onSubmit={handleSubmit(getData)} >
<Controller
control={control}
name="phone"
render={({ field: { ref, ...field } }) => (
<ReactPhoneInput {...field}
inputExtraProps={{ref, required: true, autoFocus: true }}
country={"in"}
onlyCountries={["in"]}
countryCodeEditable={false}
specialLabel={"Player Mobile Number"}
/>
)}
/>
<Button type='submit>Submit</Button>
</form>
You can use the rules prop of the <Controller /> component to define your validation rules. Check the rules section here for more info.
To display the errors you have to use formState object returned by useForm.
export default function App() {
const {
control,
handleSubmit,
formState: { errors }
} = useForm();
const onSubmit = (data) => {
console.log(data);
};
const isNumber = (number) => !isNaN(number) || "Must be a number";
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
control={control}
name="phone"
rules={{
required: { value: true, message: "Required" },
minLength: { value: 12, message: "Min Length" },
maxLength: { value: 12, message: "Max Length" },
validate: isNumber
}}
render={({ field: { ref, ...field } }) => (
<ReactPhoneInput
{...field}
inputExtraProps={{
ref,
required: true,
autoFocus: true
}}
country={"in"}
onlyCountries={["in"]}
countryCodeEditable={false}
specialLabel={"Player Mobile Number"}
/>
)}
/>
{errors.phone && <p>{errors.phone.message}</p>}
<input type="submit" />
</form>
);
}
I'm trying to use React Select with useForm and got stuck when submitting form values.
My goal is a multi value react select with a default value and onChange function to do some validations when changing (like limit the number of itens to 3).
I already tried to search the solution in others posts and did make some changes in my code but unfortunately I did not succeed.
Everything seems to work perfectly but when I submit the form, my controller results in undefined value.
import React, {useEffect, useState, useContext} from 'react'
import {useForm, Controller} from 'react-hook-form'
import axios from 'axios';
import Select from 'react-select';
import BeeUtils from '../../../utils/BeeUtils'
export default function EditCategory2({place, goBack}){
var messageFieldRequired = 'Campo Obrigatório';
const audienceOptions = [
{ value: 'Lésbicas', label: 'Lésbicas' },
{ value: 'Gays', label: 'Gays' },
{ value: 'Bissexuais', label: 'Bissexuais' },
{ value: 'Transexuais', label: 'Transexuais' },
{ value: 'Queer', label: 'Queer' },
{ value: 'Intersexo', label: 'Intersexo' },
{ value: 'Assexual', label: 'Assexual' },
{ value: 'Héteros', label: 'Héteros' },
{ value: 'Todxs', label: 'Todxs' }
]
const handleAudienceSelector = (e) => {
console.log('OK');
console.log(e);
if(e.length > 3){
e.pop();
alert('max of 3 selected');
}
}
const {register , handleSubmit, errors, setValue, getValues, setError, control} = useForm();
const requestUpdate = async (data) => {
data.createdBy = place.createdBy;
data._id = place._id;
data.recordUpdatedType = 'audience';
console.log(data);
return;
}
const selectRequired = (e) => {
console.log(e);
console.log('OK-2');
//var error = e.length == 0? messageFieldRequired : '';
//return error;
}
const onSubmit = data => {
console.log(data)
requestUpdate(data);
}
return (
<div className='cad-form'>
<form onSubmit={handleSubmit(onSubmit)}>
<div className='cad-tit-container'>
<span className='cad-titulo'> Edit Here</span>
</div>
<div className='cad-container'>
<label htmlFor='test-audience'>Audience</label>
<Controller
name="test-audience"
control={control}
rules={{ validate: selectRequired }}
render={() => (
<Select
defaultValue={[audienceOptions[0], audienceOptions[1]]}
isMulti
onChange={handleAudienceSelector}
placeholder='Select Itens'
options={audienceOptions}
className="basic-multi-select selectCustom"
classNamePrefix="select"
/>
)}
/>
{errors?.targetAudience && <p>{errors.targetAudience.message}</p>}
</div>
<div className='btn-container'>
<div className='cad-btn'><button onClick={(e) => goBack('initial')} className="btn waves-effect yellow darken-2">Voltar</button></div>
<div className='cad-btn'><button type='submit' className="btn waves-effect yellow darken-2">Salvar Alterações</button></div>
</div>
</form>
</div>
)
}
After some changes (thanks to help of the answer) I tried this code
import React, {useEffect, useState, useContext} from 'react'
import {useForm, Controller} from 'react-hook-form'
import axios from 'axios';
import Select from 'react-select';
import BeeUtils from '../../../utils/BeeUtils'
export default function EditCategory2({place, goBack}){
var messageFieldRequired = 'Campo Obrigatório';
const audienceOptions = [
{ value: 'Lésbicas', label: 'Lésbicas' },
{ value: 'Gays', label: 'Gays' },
{ value: 'Bissexuais', label: 'Bissexuais' },
{ value: 'Transexuais', label: 'Transexuais' },
{ value: 'Queer', label: 'Queer' },
{ value: 'Intersexo', label: 'Intersexo' },
{ value: 'Assexual', label: 'Assexual' },
{ value: 'Héteros', label: 'Héteros' },
{ value: 'Todxs', label: 'Todxs' }
]
const handleAudienceSelector = (e) => {
console.log('OK');
console.log(e);
if(e.length > 3){
e.pop();
alert('max of 3 selected');
}
}
const {register , handleSubmit, errors, setValue, getValues, setError, control} = useForm();
const requestUpdate = async (data) => {
data.createdBy = place.createdBy;
data._id = place._id;
data.recordUpdatedType = 'audience';
console.log(data);
return;
}
const onSubmit = data => {
console.log(data)
requestUpdate(data);
}
return (
<div className='cad-form'>
<form onSubmit={handleSubmit(onSubmit)}>
<div className='cad-tit-container'>
<span className='cad-titulo'> Edit Here</span>
</div>
<div className='cad-container'>
<label htmlFor='test-audience'>Audience</label>
<Controller
name="targetAudience"
control={control}
defaultValue={[audienceOptions[0], audienceOptions[1]]}
rules={{ required: messageFieldRequired }}
render={({ field: { onChange, value } }) => (
<Select
value={value}
onChange={onChange}
isMulti
placeholder="Select Itens"
options={audienceOptions}
className="basic-multi-select selectCustom"
classNamePrefix="select"
/>
)}
/>
</div>
<div className='btn-container'>
<div className='cad-btn'><button onClick={(e) => goBack('initial')} className="btn waves-effect yellow darken-2">Voltar</button></div>
<div className='cad-btn'><button type='submit' className="btn waves-effect yellow darken-2">Salvar Alterações</button></div>
</div>
</form>
</div>
)
}
But now I got the error: TypeError: Cannot read property 'onChange' of undefined
The reason why it isn't working is because you forgot to to link the <Controller /> component with the <Select /> component via the value and onChange properties of the render prop function from <Controller />.
<Controller
name="targetAudience"
control={control}
defaultValue={[audienceOptions[0], audienceOptions[1]]}
rules={{ required: "Campo obrigatório", validate: isOnly3Values }}
render={({ field: { onChange, value } }) => (
<Select
value={value}
onChange={onChange}
isMulti
placeholder="Select Itens"
options={audienceOptions}
className="basic-multi-select selectCustom"
classNamePrefix="select"
/>
)}
/>
You also don't need to use useState here for handling the error state as RHF already provides this functionality. For setting a field to be required, you can just set the required property of the validation object which can be passed to <Controller /> via the rules prop. Check here for more information about <Controller />. I would suggest to also use the validate function from RHF to check if the user added more than 3 items to your <Select /> and display an error message instead of using an alert.
I made some overall small changes and corrected some minor issues (e.g. the errors object is located in the formState property since v7). Feel free to write a comment if something isn't clear.
I'm looking to implement the form validation using react-hook. However, I'm facing some trouble in doing so as I've also added some stuff on my own under the handleSubmit and I'm not really sure how to go about it.
export default function Contact() {
const [message, setMessage] = useState(false);
const [alert, setAlert] = useState(true);
const { register, errors} = useForm();
const [showElement, setShowElement] = React.useState(false);
const handleSubmit = (e) => {
e.preventDefault();
emailjs.sendForm('', '', e.target, '')
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
e.target.reset();
setMessage(true);
setShowElement(true);
setTimeout(function () {
setShowElement(false);
}, 4000);
};
const onSubmit= data=>{
console.log(data);
}
return (
<div className="right">
<h2>Contact Me</h2>
<form onSubmit={handleSubmit} id="contactform">
<input type="text" placeholder="Name" name="name" ref={register({required: true, minLength: 2})}
required />
<button type="submit">Send</button>
</form>
{showElement ? (
<div className="submitmsg">
{message && (
<span> Messaged received. I'll respond to your query ASAP! </span>
)}
</div>
) : (
<div> </div>
)}{" "}
</div>
)
}
Thank you!
React hook form provides the handeSubmit method that receives the form data after validations. Also, you must use the errors object to show errors in the UI.
Here is the sandbox link: https://codesandbox.io/s/exciting-dust-df5ft?file=/src/App.js
I have updated your code accordingly:
import { useState } from "react";
import React from "react";
import emailjs from "emailjs-com";
import { useForm } from "react-hook-form";
export default function Contact() {
const [message, setMessage] = useState(false);
const {
register,
handleSubmit,
formState: { errors }
} = useForm();
const [showElement, setShowElement] = React.useState(false);
const onSubmit = (data) => {
emailjs
.send(
"service_t1ccrgq",
"template_gmmcyzr",
data,
"user_d0vUwhmqvbIYhEsyZF8tu"
)
.then(
(result) => {
console.log(result.text);
},
(error) => {
console.log(error.text);
}
);
setMessage(true);
setShowElement(true);
setTimeout(function () {
setShowElement(false);
}, 4000);
};
return (
<div className="contact" id="contact">
<div className="left">
<img className="contactme" src="asset/email.gif" />
</div>
<div className="right">
<h2>Contact Me</h2>
<form onSubmit={handleSubmit(onSubmit)} id="contactform">
<input
type="text"
placeholder="Name"
name="name"
{...register("name", {
required: "Name is Required",
minLength: {
value: 3,
message: "Should be greater than 3 characters"
}
})}
/>
<input
type="tel"
placeholder="Mobile Number"
name="mobile"
{...register("mobile", {
required: "Mobile Number is Required",
minLength: {
value: 3,
message: "Should be greater than 3 characters"
}
})}
/>
<input
type="text"
placeholder="Email"
name="email"
{...register("email", {
required: "Email is Required",
minLength: {
value: 3,
message: "Should be greater than 3 characters"
}
})}
/>
<textarea
placeholder="Message"
required
name="message"
{...register("message", {
required: "Message is Required",
minLength: {
value: 3,
message: "Should be greater than 3 characters"
}
})}
></textarea>
<button type="submit">Send</button>
</form>
{showElement ? (
<div className="submitmsg">
{message && (
<span> Messaged received. I'll respond to your query ASAP! </span>
)}
</div>
) : (
<div> </div>
)}{" "}
</div>
{errors.name && (
<div>
<span>{errors.name.message}</span>
</div>
)}
{errors.message && (
<div>
<span>{errors.message.message}</span>
</div>
)}
{errors.email && (
<div>
<span>{errors.email.message}</span>
</div>
)}
{errors.mobile && (
<div>
<span>{errors.mobile.message}</span>
</div>
)}
</div>
);
}
You have to first initialize handleSubmit as below.
const {handleSubmit} = useForm();
Then in the form, onSubmit should be as below.
<form onSubmit={handleSubmit(onSubmit)}>
"onSubmit" is the method that is used to write the code in submitting form.
Regards.
In your code, it should be as below.
const onSubmit = (e) => {
e.preventDefault();
emailjs.sendForm('', '', e.target, '')
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
e.target.reset();
setMessage(true);
setShowElement(true);
setTimeout(function () {
setShowElement(false);
}, 4000);
};
I'm trying to figure out how to use react-hook-form with antd front end.
I have made this form and it seems to be working (it's part 1 of a multipart form wizard) except that the error messages do not display.
Can anyone see what I've done wrong in merging these two form systems?
I'm not getting any errors, but I think I have asked for both form fields to be required but if I press submit without completing them the error messages are not displayed.
import React from "react";
import useForm from "react-hook-form";
import { BrowserRouter as Router, Route } from "react-router-dom";
import { StateMachineProvider, createStore } from "little-state-machine";
import { withRouter } from "react-router-dom";
import { useStateMachine } from "little-state-machine";
import updateAction from "./updateAction";
import { Button, Form, Input, Divider, Layout, Typography, Skeleton, Switch, Card, Icon, Avatar } from 'antd';
const { Content } = Layout
const { Text, Paragraph } = Typography;
const { Meta } = Card;
createStore({
data: {}
});
const General = props => {
const { register, handleSubmit, errors } = useForm();
const { action } = useStateMachine(updateAction);
const onSubit = data => {
action(data);
props.history.push("./ProposalMethod");
};
return (
<div>
<Content
style={{
background: '#fff',
padding: 24,
margin: "auto",
minHeight: 280,
width: '70%'
}}
>
<Form onSubmit={handleSubmit(onSubit)}>
<h2>Part 1: General</h2>
<Form.Item label="Title" >
<Input
name="title"
placeholder="Add a title"
ref={register({ required: true })}
/>
{errors.title && 'A title is required.'}
</Form.Item>
<Form.Item label="Subtitle" >
<Input
name="subtitle"
placeholder="Add a subtitle"
ref={register({ required: true })}
/>
{errors.subtitle && 'A subtitle is required.'}
</Form.Item>
<Form.Item>
<Button type="secondary" htmlType="submit">
Next
</Button>
</Form.Item>
</Form>
</Content>
</div>
);
};
export default withRouter(General);
react-hook-form author here. Antd Input component doesn't really expose inner ref, so you will have to register during useEffect, and update value during onChange, eg:
const { register, setValue } = useForm();
useEffect(() => {
register({ name: 'yourField' }, { required: true });
}, [])
<Input name="yourField" onChange={(e) => setValue('yourField', e.target.value)}
i have built a wrapper component to make antd component integration easier: https://github.com/react-hook-form/react-hook-form-input
import React from 'react';
import useForm from 'react-hook-form';
import { RHFInput } from 'react-hook-form-input';
import Select from 'react-select';
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];
function App() {
const { handleSubmit, register, setValue, reset } = useForm();
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<RHFInput
as={<Select options={options} />}
rules={{ required: true }}
name="reactSelect"
register={register}
setValue={setValue}
/>
<button
type="button"
onClick={() => {
reset({
reactSelect: '',
});
}}
>
Reset Form
</button>
<button>submit</button>
</form>
);
}
This is my working approach:
const Example = () => {
const { control, handleSubmit, errors } = useForm()
const onSubmit = data => console.log(data)
console.log(errors)
return (
<Form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="email"
control={control}
rules={{ required: "Please enter your email address" }}
as={
<Form.Item
label="name"
validateStatus={errors.email && "error"}
help={errors.email && errors.email.message}
>
<Input />
</Form.Item>
}
/>
<Button htmlType="submit">Submit</Button>
</Form>
)
}
On writing such code:
<Input
name="subtitle"
placeholder="Add a subtitle"
ref={register({ required: true })}
/>
You assume that Input reference is bound to input, but that's not true.
In fact, you need to bind it to inputRef.input.
You can check it with the next code:
const App = () => {
const inputRef = useRef();
const inputRefHtml = useRef();
useEffect(() => {
console.log(inputRef.current);
console.log(inputRefHtml.current);
});
return (
<FlexBox>
<Input ref={inputRef} />
<input ref={inputRefHtml} />
</FlexBox>
);
};
# Logs
Input {props: Object, context: Object, refs: Object, updater: Object, saveClearableInput: function ()…}
<input></input>
Note that antd is a complete UI library (using 3rd party "helpers" should "turn a red light"), in particular, Form has a validator implemented, you can see a variety of examples in docs.
In Ant Design v4.x + react-hook-form v6.x. We can implement as normally
import { useForm, Controller, SubmitHandler } from 'react-hook-form';
import * as yup from 'yup';
import { yupResolver } from '#hookform/resolvers/yup';
import { useIntl } from 'react-intl';
import { Input, Button, Form } from 'antd';
const SignInSchema = yup.object().shape({
email: yup.string().email().required(),
password: yup.string().required('required').min(6, 'passwordMin'),
});
interface PropTypes {
defaultValues?: {
email: string;
password: string;
};
handleFormSubmit: SubmitHandler<{ email: string; password: string }>;
}
function SignInForm({ defaultValues, handleFormSubmit }: PropTypes) {
const intl = useIntl();
const { handleSubmit, control, errors } = useForm({
defaultValues,
resolver: yupResolver(SignInSchema),
});
return (
<Form onFinish={handleSubmit(handleFormSubmit)}>
<Form.Item
validateStatus={errors && errors['email'] ? 'error' : ''}
help={errors.email?.message}
>
<Controller
as={Input}
name="email"
autoComplete="email"
control={control}
placeholder={intl.formatMessage({ id: 'AUTH_INPUT_EMAIL' })}
/>
</Form.Item>
<Form.Item
validateStatus={errors && errors['password'] ? 'error' : ''}
help={errors.password?.message}
>
<Controller
as={Input}
name="password"
type="password"
control={control}
autoComplete="new-password"
defaultValue=""
placeholder={intl.formatMessage({ id: 'AUTH_INPUT_PASSWORD' })}
/>
</Form.Item>
<Button type="primary" htmlType="submit">
{intl.formatMessage({ id: 'SIGN_IN_SUBMIT_BUTTON' })}
</Button>
</Form>
);
}
export default SignInForm;
In case anyone is still interested in getting close to the default styles of the Form Inputs provided by Ant, here's how I got it to work:
import { Form, Button, Input } from 'antd';
import { useForm, Controller } from 'react-hook-form';
function MyForm() {
const { control, handleSubmit, errors, setValue } = useForm();
const emailError = errors.email && 'Enter your email address';
const onSubmit = data => { console.log(data) };
const EmailInput = (
<Form.Item>
<Input
type="email"
placeholder="Email"
onChange={e => setValue('email', e.target.value, true)}
onBlur={e => setValue('email', e.target.value, true)}
/>
</Form.Item>
);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
as={EmailInput}
name="email"
control={control}
defaultValue=""
rules={{
required: true
}}
validateStatus={emailError ? 'error' : ''}
help={emailError}
/>
<Button block type="primary" htmlType="submit">
Submit
</Button>
</form>
);
}
Codesandbox sample