Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I set checkbox to checked state in a React Hook Form?

I am trying out React-Hook-form

The simple code for the checkbox is as below:

import React from 'react'
import { useForm } from 'react-hook-form'

export default function App() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm()
  const onSubmit = (data: any) => console.log(data)
  console.log(errors)

  return (
    <div className='mx-auto justify-center p-32 flex'>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div className='p-2'>
          <label htmlFor=''>January</label>
          <input
            type='checkbox'
            placeholder='January'
            {...register('January', {})}
            className='mx-3'
            checked
          />
        </div>
        <div className='p-2'>
          <label htmlFor=''>February</label>
          <input
            type='checkbox'
            placeholder='February'
            {...register('February', {})}
            className='mx-3'
          />
        </div>
        <input type='submit' />
      </form>
    </div>
  )
}

I can submit the form correctly but I have like the January checkbox to start off as a checked box but when I put 'checked' as shown in the code, I somehow could not 'uncheck' it.

I seem to be missing something and any help would be greatly appreciated.

like image 201
Daryl Wong Avatar asked Sep 09 '25 18:09

Daryl Wong


2 Answers

The issue with passing checked is that it takes control away from useForm to manage the checkbox. useForm register() uses change handlers (onChange/onBlur) to update the checked (or value for non-checkboxes) attributes of the actual DOM <input> element.

By passing the checked prop you are overriding the checked DOM attribute that is managed by useForm. This causes the checkbox to be unable to change state.


Now that I've cleared up why this issue happens let's move on to the solution. This can be solved in two ways:

  1. useForm allows you to pass a default values when you initially call the hook.

    const {
      register,
      handleSubmit,
      formState: { errors },
    } = useForm({ defaultValues: { January: true } });
    
    // ...
    
    <input
      type="checkbox"
      {...register("January")}
    />
    
  2. Or use the defaultChecked property of an <input type="checkbox" /> this holds the initial checked value and doesn't override the current value like checked does.

    const {
      register,
      handleSubmit,
      formState: { errors },
    } = useForm();
    
    // ...
    
    <input
      type="checkbox"
      {...register("January")}
      defaultChecked
    />
    

Note that it's not a good idea to combine the two methods. Use one or the other. The useForm says the following in the defaultValues section:

The defaultValues prop populates the entire form with default values. It supports both synchronous and asynchronous assignment of default values. While you can set an input's default value using defaultValue or defaultChecked (as detailed in the official React documentation), it is recommended to use defaultValues for the entire form.


In the given scenario it's probably better to use an array of selected values ["January", "March"] instead of an object { January: true, February: false, March: true }.

You can get the array result by using an (empty) array as the default value, and registering the checkboxes under the same name. If any values are present inside the array, they will be checked by default. The values used in the array will match the checkbox value property.

const {
  register,
  handleSubmit,
  formState: { errors },
} = useForm({
  defaultValues: { months: ["January"] }
  // mark months as array and ^ check the checkbox with value "January"
});

// ...

// add the `value` prop to the checkboxes
<input
  type="checkbox"
  value="January"
  {...register("months")}
/>
<input
  type="checkbox"
  value="February"
  {...register("months")}
/>
like image 148
3limin4t0r Avatar answered Sep 12 '25 10:09

3limin4t0r


if you are using react material ui with react-hook-form here is a simplest way to make it work

import {
  Box
  Checkbox,
  FormControlLabel,
} from '@mui/material'
...
const {
  handleSubmit,
  control,
  formState: { errors },
} = useForm({
})
...

<Box>
<Controller
  control={control}
  name={`${dimension.id}-${dimension.name}`}
  defaultValue={false}
  render={({ field: { onChange, value } }) => (
    <FormControlLabel
      control={
        <Checkbox checked={value} onChange={onChange} />
      }
    />
  )}
/>
</Box>
like image 38
DINA TAKLIT Avatar answered Sep 12 '25 08:09

DINA TAKLIT