ReactJS – How to validate a form?

Use react-hook-form

Basic

Install

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
yarn add react-hook-form
yarn add react-hook-form
yarn add react-hook-form

Usage

  • Create form elements with unique name props
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
...
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
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
...
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
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
...
<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
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<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?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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

Be the first to comment

Leave a Reply

Your email address will not be published.


*