Published on

Fixing React Hook Form Validation in onBlur Mode

Authors
  • Name
    Ripal & Zalak
    Twitter

Fixing React Hook Form Validation in onBlur Mode

When working with React Hook Form and Yup for validation, you may encounter a scenario where validation behaves unexpectedly in onBlur mode. This blog post will help you understand why this happens and how to fix it.

Problem Description

In a React application, consider the following code snippet using react-hook-form with onBlur validation mode and Yup schema:

import React, { useState } from 'react'
import { useForm } from 'react-hook-form'
import { yupResolver } from '@hookform/resolvers/yup'
import * as yup from 'yup'
import {
  Checkbox,
  Button,
  FormControl,
  FormLabel,
  FormGroup,
  FormControlLabel,
  FormHelperText,
} from '@mui/material'

const schema = yup.object().shape({
  option: yup.array().max(5, 'You can select up to 5 options only.'),
})

function App() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({
    mode: 'onBlur',
    resolver: yupResolver(schema),
  })

  const onSubmit = (data) => {
    alert(JSON.stringify(data))
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <FormControl component="fieldset" error={!!errors.option}>
        <FormLabel component="legend">Select up to 5 options:</FormLabel>
        <FormGroup>
          {[...Array(8)].map((_, index) => (
            <FormControlLabel
              key={index}
              control={
                <Checkbox name="option" value={`Option${index + 1}`} {...register('option')} />
              }
              label={`Option ${index + 1}`}
            />
          ))}
        </FormGroup>
        <FormHelperText>
          {errors.option?.message || 'You can select up to 5 categories.'}
        </FormHelperText>
      </FormControl>
      <Button type="submit">Submit</Button>
    </form>
  )
}

export default App

Issue: Validation errors occur only after selecting the 7th checkbox instead of the 6th. This happens because onBlur triggers validation when an input loses focus, but it evaluates the previous state of the form instead of the current state.

Solution

To resolve this, switch the mode of useForm to onChange or all.

Updating to onChange Mode

const {
  register,
  handleSubmit,
  formState: { errors },
} = useForm({
  mode: 'onChange',
  resolver: yupResolver(schema),
})

Benefits:

  • Triggers validation whenever a checkbox is checked or unchecked.
  • Ensures the form always evaluates the latest state.

Using all Mode for Comprehensive Validation

const {
  register,
  handleSubmit,
  formState: { errors },
} = useForm({
  mode: 'all',
  resolver: yupResolver(schema),
})

Benefits:

  • Combines onBlur and onChange validation modes.
  • Ideal for workflows that require both immediate feedback and focus-based validation.

Alternative: Manually Triggering Validation for Controlled Components

If you are using controlled components, ensure onBlur is explicitly wired to the field’s validation function.

import { Controller, useFormContext } from 'react-hook-form'

const MyControlledField = ({ fieldName }) => {
  const { control } = useFormContext()

  return (
    <Controller
      name={fieldName}
      control={control}
      render={({ field: { onChange, onBlur, value } }) => (
        <Checkbox checked={!!value} onChange={onChange} onBlur={onBlur} />
      )}
    />
  )
}

FAQs

Why does validation fail in **onBlur** mode?

onBlur mode triggers validation only when an input loses focus. If the validation depends on the state of multiple inputs, it may not capture changes accurately.

Which validation mode is best for performance?

Use onSubmit for minimal re-renders, or onChange if real-time validation is required.

Can I combine validation modes?

Yes, the all mode combines onBlur and onChange for comprehensive validation.