Use react-hook-form
Basic
Install
yarn add react-hook-form
yarn add react-hook-form
yarn add react-hook-form
Usage
- Create form elements with unique name props
...
return (
<form>
<input name="name" />
<input type="email" name="email" />
<input type="password" name="password" />
<button>Submit</button>
</form>
...
...
return (
<form>
<input name="name" />
<input type="email" name="email" />
<input type="password" name="password" />
<button>Submit</button>
</form>
...
... return ( <form> <input name="name" /> <input type="email" name="email" /> <input type="password" name="password" /> <button>Submit</button> </form> ...
- Add handleSubmit method to manage form submission
import { useForm } from "react-hook-form";
...
const { register, handleSubmit } = useForm();
const onFormSubmit = data => console.log(data);
const onErrors = errors => console.error(errors);
return (
<form onSubmit={handleSubmit(onFormSubmit, onErrors)}>
...
</form>
);
import { useForm } from "react-hook-form";
...
const { register, handleSubmit } = useForm();
const onFormSubmit = data => console.log(data);
const onErrors = errors => console.error(errors);
return (
<form onSubmit={handleSubmit(onFormSubmit, onErrors)}>
...
</form>
);
import { useForm } from "react-hook-form"; ... const { register, handleSubmit } = useForm(); const onFormSubmit = data => console.log(data); const onErrors = errors => console.error(errors); return ( <form onSubmit={handleSubmit(onFormSubmit, onErrors)}> ... </form> );
- Register input fields into React Hook Form by using name values
import { useForm } from "react-hook-form";
...
const { register, handleSubmit } = useForm();
...
return (
<form onSubmit={handleSubmit(onFormSubmit, onErrors)}>
<input name="name" {...register('name')} />
<input type="email" name="email" {...register('email')} />
<input type="password" name="password" {...register('password')} />
<button>Submit</button>
</form>
);
import { useForm } from "react-hook-form";
...
const { register, handleSubmit } = useForm();
...
return (
<form onSubmit={handleSubmit(onFormSubmit, onErrors)}>
<input name="name" {...register('name')} />
<input type="email" name="email" {...register('email')} />
<input type="password" name="password" {...register('password')} />
<button>Submit</button>
</form>
);
import { useForm } from "react-hook-form"; ... const { register, handleSubmit } = useForm(); ... return ( <form onSubmit={handleSubmit(onFormSubmit, onErrors)}> <input name="name" {...register('name')} /> <input type="email" name="email" {...register('email')} /> <input type="password" name="password" {...register('password')} /> <button>Submit</button> </form> );
- Create form validation object
...
const registerOptions = {
name: { required: "Name is required" },
email: { required: "Email is required" },
password: {
required: "Password is required",
minLength: {
value: 8,
message: "Password must have at least 8 characters"
}
}
};
...
...
const registerOptions = {
name: { required: "Name is required" },
email: { required: "Email is required" },
password: {
required: "Password is required",
minLength: {
value: 8,
message: "Password must have at least 8 characters"
}
}
};
...
... const registerOptions = { name: { required: "Name is required" }, email: { required: "Email is required" }, password: { required: "Password is required", minLength: { value: 8, message: "Password must have at least 8 characters" } } }; ...
- Apply validation for form element
...
<form onSubmit={handleSubmit(handleRegistration, handleError)}>
<input name="name" type="text" {...register('name', registerOptions.name) }/>
{errors?.name && errors.name.message}
<input
type="email"
name="email"
{...register('email', registerOptions.email)}
/>
{errors?.email && errors.email.message}
<input
type="password"
name="password"
{...register('password', registerOptions.password)}
/>
{errors?.password && errors.password.message}
<button>Submit</button>
</form>
...
...
<form onSubmit={handleSubmit(handleRegistration, handleError)}>
<input name="name" type="text" {...register('name', registerOptions.name) }/>
{errors?.name && errors.name.message}
<input
type="email"
name="email"
{...register('email', registerOptions.email)}
/>
{errors?.email && errors.email.message}
<input
type="password"
name="password"
{...register('password', registerOptions.password)}
/>
{errors?.password && errors.password.message}
<button>Submit</button>
</form>
...
... <form onSubmit={handleSubmit(handleRegistration, handleError)}> <input name="name" type="text" {...register('name', registerOptions.name) }/> {errors?.name && errors.name.message} <input type="email" name="email" {...register('email', registerOptions.email)} /> {errors?.email && errors.email.message} <input type="password" name="password" {...register('password', registerOptions.password)} /> {errors?.password && errors.password.message} <button>Submit</button> </form> ...
- Or catch error state like this
const errorNameMessage = errors['name']?.message;
const hasNameError = !!(errors && errorNameMessage);
return <form>
<input name="name" type="text" {...register('name', registerOptions.name) }/>
{hasNameError && errorNameMessage}
...
const errorNameMessage = errors['name']?.message;
const hasNameError = !!(errors && errorNameMessage);
return <form>
<input name="name" type="text" {...register('name', registerOptions.name) }/>
{hasNameError && errorNameMessage}
...
const errorNameMessage = errors['name']?.message; const hasNameError = !!(errors && errorNameMessage); return <form> <input name="name" type="text" {...register('name', registerOptions.name) }/> {hasNameError && errorNameMessage} ...
How to make a submit button inside a form?
<button type='submit'>Click me</button>
<button type='submit'>Click me</button>
<button type='submit'>Click me</button>
Typescript template
How to create main component?
import InputForm from 'src/components/InputForm'
import { useForm, SubmitHandler } from 'react-hook-form'
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
type TFormFields = {
'name-first-name': string,
}
const registerRules = {
firstName: { required: 'First name is required' },
gender: { required: 'Gender is required' },
}
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
const Details = () => {
const {
control,
register,
handleSubmit,
formState: { errors },
} = useForm<TFormFields>()
const onSubmit: SubmitHandler<TFormFields> = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<InputForm
name='name-first-name'
register={register}
rules={registerRules.firstName}
errors={errors}
/>
<SelectBox
placeHolder='Gender'
name='name-select-gender'
errors={errors}
control={control}
options={[
{ value: 'male', label: 'Male' },
{ value: 'female', label: 'Female' },
]}
rules={registerRules.gender}
/>
</form>
)
}
export default Details
import InputForm from 'src/components/InputForm'
import { useForm, SubmitHandler } from 'react-hook-form'
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
type TFormFields = {
'name-first-name': string,
}
const registerRules = {
firstName: { required: 'First name is required' },
gender: { required: 'Gender is required' },
}
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
const Details = () => {
const {
control,
register,
handleSubmit,
formState: { errors },
} = useForm<TFormFields>()
const onSubmit: SubmitHandler<TFormFields> = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<InputForm
name='name-first-name'
register={register}
rules={registerRules.firstName}
errors={errors}
/>
<SelectBox
placeHolder='Gender'
name='name-select-gender'
errors={errors}
control={control}
options={[
{ value: 'male', label: 'Male' },
{ value: 'female', label: 'Female' },
]}
rules={registerRules.gender}
/>
</form>
)
}
export default Details
import InputForm from 'src/components/InputForm' import { useForm, SubmitHandler } from 'react-hook-form' //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// type TFormFields = { 'name-first-name': string, } const registerRules = { firstName: { required: 'First name is required' }, gender: { required: 'Gender is required' }, } //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// const Details = () => { const { control, register, handleSubmit, formState: { errors }, } = useForm<TFormFields>() const onSubmit: SubmitHandler<TFormFields> = (data) => console.log(data) return ( <form onSubmit={handleSubmit(onSubmit)}> <InputForm name='name-first-name' register={register} rules={registerRules.firstName} errors={errors} /> <SelectBox placeHolder='Gender' name='name-select-gender' errors={errors} control={control} options={[ { value: 'male', label: 'Male' }, { value: 'female', label: 'Female' }, ]} rules={registerRules.gender} /> </form> ) } export default Details
How to create a custom Input text?
import { ReactElement } from 'react'
import {
DeepMap,
FieldError,
FieldValues,
Path,
RegisterOptions,
UseFormRegister,
} from 'react-hook-form'
require('./index.scss')
type TInputProps<TSomething> = {
placeHolder: string,
name?: Path<TSomething>,
rules?: RegisterOptions,
register?: UseFormRegister<TSomething>,
errors?: Partial<DeepMap<FieldValues, FieldError>>
}
const InputForm = <TSomething extends unknown>({
name,
rules = {},
register,
errors = {},
placeHolder
}: TInputProps<TSomething>): ReactElement => {
const errorMessage = errors[name]?.message
const hasError = !!(errors && errorMessage)
return (
<div className={hasError ? `preferences__profile--input-box--error` : `preferences__profile--input-box`}>
<input
placeholder={placeHolder}
name={name || ''}
{...(register && register(name, rules))}
/>
{hasError && <p>{errorMessage}</p>}
</div>
)
}
export default InputForm
import { ReactElement } from 'react'
import {
DeepMap,
FieldError,
FieldValues,
Path,
RegisterOptions,
UseFormRegister,
} from 'react-hook-form'
require('./index.scss')
type TInputProps<TSomething> = {
placeHolder: string,
name?: Path<TSomething>,
rules?: RegisterOptions,
register?: UseFormRegister<TSomething>,
errors?: Partial<DeepMap<FieldValues, FieldError>>
}
const InputForm = <TSomething extends unknown>({
name,
rules = {},
register,
errors = {},
placeHolder
}: TInputProps<TSomething>): ReactElement => {
const errorMessage = errors[name]?.message
const hasError = !!(errors && errorMessage)
return (
<div className={hasError ? `preferences__profile--input-box--error` : `preferences__profile--input-box`}>
<input
placeholder={placeHolder}
name={name || ''}
{...(register && register(name, rules))}
/>
{hasError && <p>{errorMessage}</p>}
</div>
)
}
export default InputForm
import { ReactElement } from 'react' import { DeepMap, FieldError, FieldValues, Path, RegisterOptions, UseFormRegister, } from 'react-hook-form' require('./index.scss') type TInputProps<TSomething> = { placeHolder: string, name?: Path<TSomething>, rules?: RegisterOptions, register?: UseFormRegister<TSomething>, errors?: Partial<DeepMap<FieldValues, FieldError>> } const InputForm = <TSomething extends unknown>({ name, rules = {}, register, errors = {}, placeHolder }: TInputProps<TSomething>): ReactElement => { const errorMessage = errors[name]?.message const hasError = !!(errors && errorMessage) return ( <div className={hasError ? `preferences__profile--input-box--error` : `preferences__profile--input-box`}> <input placeholder={placeHolder} name={name || ''} {...(register && register(name, rules))} /> {hasError && <p>{errorMessage}</p>} </div> ) } export default InputForm
How to create a custom Select box with react-select?
import { ReactElement } from 'react'
import Select, { components } from 'react-select'
import { Control, Controller, DeepMap, FieldError, FieldValues, Path, RegisterOptions } from 'react-hook-form'
require('./index.scss')
interface Props<TSomething> {
placeHolder: string,
options: Array<any>,
name?: Path<TSomething>,
rules?: RegisterOptions,
control?: Control<TSomething, any>,
errors?: Partial<DeepMap<FieldValues, FieldError>>,
}
let hasError: boolean = false
const SelectBox = <TSomething extends unknown>({
placeHolder,
options,
rules,
control,
errors,
name,
}: Props<TSomething>): ReactElement => {
const errorMessage = errors?.[name]?.message
hasError = !!(errors && errorMessage)
return <>
<Controller
control={control}
name={name}
rules={rules}
render={({ field: { onChange, value, name, ref } }) => {
const currentSelection = options.find(
(c) => c.value === value
)
const handleSelectChange = (selectedOption: { value: string }) => {
onChange(selectedOption?.value);
}
return <div>
<Select
className={'preferences__select-box'}
components={{
DropdownIndicator: CustomDropdownIndicator,
IndicatorSeparator: () => null,
}}
styles={customStyles}
options={options}
placeholder={placeHolder}
onChange={handleSelectChange}
value={currentSelection}
/>
{hasError && <p className='preferences__profile--error-text'>{errorMessage}</p>}
</div>
}}
/>
</>
}
const customStyles = {
control: (provided: any) => ({
...provided,
width: '100%',
height: '48px',
paddingLeft: '7px',
border: hasError ? '1px solid #ED1C24' : '1px solid #DEDEDE',
fontSize: '14px',
color: '#333333',
}),
placeholder: (defaultStyles: any) => {
return {
...defaultStyles,
color: '#999999',
}
},
option: (provided: any, state: { isSelected: any }) => ({
...provided,
color: '#333333',
}),
}
const CustomDropdownIndicator = (props: any) => {
return (
<components.DropdownIndicator {...props}>
<YourOwnIcon />
</components.DropdownIndicator>
)
}
export default SelectBox
import { ReactElement } from 'react'
import Select, { components } from 'react-select'
import { Control, Controller, DeepMap, FieldError, FieldValues, Path, RegisterOptions } from 'react-hook-form'
require('./index.scss')
interface Props<TSomething> {
placeHolder: string,
options: Array<any>,
name?: Path<TSomething>,
rules?: RegisterOptions,
control?: Control<TSomething, any>,
errors?: Partial<DeepMap<FieldValues, FieldError>>,
}
let hasError: boolean = false
const SelectBox = <TSomething extends unknown>({
placeHolder,
options,
rules,
control,
errors,
name,
}: Props<TSomething>): ReactElement => {
const errorMessage = errors?.[name]?.message
hasError = !!(errors && errorMessage)
return <>
<Controller
control={control}
name={name}
rules={rules}
render={({ field: { onChange, value, name, ref } }) => {
const currentSelection = options.find(
(c) => c.value === value
)
const handleSelectChange = (selectedOption: { value: string }) => {
onChange(selectedOption?.value);
}
return <div>
<Select
className={'preferences__select-box'}
components={{
DropdownIndicator: CustomDropdownIndicator,
IndicatorSeparator: () => null,
}}
styles={customStyles}
options={options}
placeholder={placeHolder}
onChange={handleSelectChange}
value={currentSelection}
/>
{hasError && <p className='preferences__profile--error-text'>{errorMessage}</p>}
</div>
}}
/>
</>
}
const customStyles = {
control: (provided: any) => ({
...provided,
width: '100%',
height: '48px',
paddingLeft: '7px',
border: hasError ? '1px solid #ED1C24' : '1px solid #DEDEDE',
fontSize: '14px',
color: '#333333',
}),
placeholder: (defaultStyles: any) => {
return {
...defaultStyles,
color: '#999999',
}
},
option: (provided: any, state: { isSelected: any }) => ({
...provided,
color: '#333333',
}),
}
const CustomDropdownIndicator = (props: any) => {
return (
<components.DropdownIndicator {...props}>
<YourOwnIcon />
</components.DropdownIndicator>
)
}
export default SelectBox
import { ReactElement } from 'react' import Select, { components } from 'react-select' import { Control, Controller, DeepMap, FieldError, FieldValues, Path, RegisterOptions } from 'react-hook-form' require('./index.scss') interface Props<TSomething> { placeHolder: string, options: Array<any>, name?: Path<TSomething>, rules?: RegisterOptions, control?: Control<TSomething, any>, errors?: Partial<DeepMap<FieldValues, FieldError>>, } let hasError: boolean = false const SelectBox = <TSomething extends unknown>({ placeHolder, options, rules, control, errors, name, }: Props<TSomething>): ReactElement => { const errorMessage = errors?.[name]?.message hasError = !!(errors && errorMessage) return <> <Controller control={control} name={name} rules={rules} render={({ field: { onChange, value, name, ref } }) => { const currentSelection = options.find( (c) => c.value === value ) const handleSelectChange = (selectedOption: { value: string }) => { onChange(selectedOption?.value); } return <div> <Select className={'preferences__select-box'} components={{ DropdownIndicator: CustomDropdownIndicator, IndicatorSeparator: () => null, }} styles={customStyles} options={options} placeholder={placeHolder} onChange={handleSelectChange} value={currentSelection} /> {hasError && <p className='preferences__profile--error-text'>{errorMessage}</p>} </div> }} /> </> } const customStyles = { control: (provided: any) => ({ ...provided, width: '100%', height: '48px', paddingLeft: '7px', border: hasError ? '1px solid #ED1C24' : '1px solid #DEDEDE', fontSize: '14px', color: '#333333', }), placeholder: (defaultStyles: any) => { return { ...defaultStyles, color: '#999999', } }, option: (provided: any, state: { isSelected: any }) => ({ ...provided, color: '#333333', }), } const CustomDropdownIndicator = (props: any) => { return ( <components.DropdownIndicator {...props}> <YourOwnIcon /> </components.DropdownIndicator> ) } export default SelectBox
Leave a Reply