ui icon indicating copy to clipboard operation
ui copied to clipboard

Unable to reset the Select component with React Hook Form

Open stevenspads opened this issue 1 year ago • 39 comments

Calling form.reset() (React Hook Form reset method) does not reset the value selected by the user in the Select.

Here's my useForm hook usage:

const form = useForm<z.infer<typeof someSchema>>({
    resolver: zodResolver(someSchema),
})

Here's my submit handler:

async function onSubmit(values: z.infer<typeof someSchema>) {
  form.reset()
}

Here's my Select field:

<Form {...form}>
  <form
    onSubmit={form.handleSubmit(onSubmit)}
  >
    <FormField
      control={form.control}
      name="type"
      render={({ field }) => (
        <FormItem>
          <FormLabel>Type</FormLabel>
          <Select onValueChange={field.onChange} defaultValue={field.value}>
            <FormControl>
              <SelectTrigger>
                <SelectValue placeholder="Select something" />
              </SelectTrigger>
            </FormControl>
            <SelectContent>
              <SelectItem value="A">
                A
              </SelectItem>
              <SelectItem value="B">
                B
              </SelectItem>
            </SelectContent>
          </Select>
        </FormItem>
      )}
    />
    <Button type="submit">
       Submit
     </Button>
  </form>
</Form>

stevenspads avatar Jun 07 '23 02:06 stevenspads

i think you need to pass defaulValues

form.reset(defaultValues)

jl-calda avatar Jun 07 '23 10:06 jl-calda

Thanks @jl-calda. I had tried this way as well and still got the same result.

const defaultValues = {
    type: undefined,
}

// ...

form.reset(defaultValues);

stevenspads avatar Jun 07 '23 14:06 stevenspads

Try setting it up like this

const form = useForm<z.infer<typeof someSchema>>({
    resolver: zodResolver(someSchema),
    defaultValues: {
        type: "A"
    }
})

If you want to have also unset state, so there is option A,B or not selected, you can make "type" nullable in your zod schema and set defaultValue to null.

Then just call reset() without providing any parameters if you want to reset whole form

LukasPokryvka avatar Jun 07 '23 20:06 LukasPokryvka

Try setting it up like this

const form = useForm<z.infer<typeof someSchema>>({
    resolver: zodResolver(someSchema),
    defaultValues: {
        type: "A"
    }
})

If you want to have also unset state, so there is option A,B or not selected, you can make "type" nullable in your zod schema and set defaultValue to null.

Then just call reset() without providing any parameters if you want to reset whole form

I tried doing this and I does reset the values however it doesn't the entered value on the input field resulting in something like this image

thequantumquirk avatar Jun 13 '23 14:06 thequantumquirk

Hey guys, there is a bug in Radix if you want to reset the value and show the placeholder again. It was fixed in https://github.com/radix-ui/primitives/pull/2174 and you can reset to placeholder using "". For now, it's only available on RC https://www.npmjs.com/package/@radix-ui/react-select?activeTab=versions

joaom00 avatar Jun 13 '23 20:06 joaom00

I also encountered such a problem, my code is:

const form = useForm<z.infer<typeof formSchema>>({
  resolver: zodResolver(formSchema),
  defaultValues: {
    content: "",
  },
})

I used form.reset() and it didn't work. 😢

evanlong0803 avatar Jun 26 '23 07:06 evanlong0803

@evanlong0926 Did you install the RC? v2.0.0-rc.7

joaom00 avatar Jun 26 '23 13:06 joaom00

@evanlong0926 Did you install the RC? v2.0.0-rc.7

No, I only have the Textarea component in my form.

evanlong0803 avatar Jun 26 '23 13:06 evanlong0803

Try setting it up like this

const form = useForm<z.infer<typeof someSchema>>({
    resolver: zodResolver(someSchema),
    defaultValues: {
        type: "A"
    }
})

If you want to have also unset state, so there is option A,B or not selected, you can make "type" nullable in your zod schema and set defaultValue to null. Then just call reset() without providing any parameters if you want to reset whole form

I tried doing this and I does reset the values however it doesn't the entered value on the input field resulting in something like this image

Can you provide som code?

LukasPokryvka avatar Jun 26 '23 13:06 LukasPokryvka

I have installed the npm i @radix-ui/[email protected]

but it still cannot reset the Select in Form Component,

Can anyone suggest a solution for me?

My Select Option cannot be null

apexbb avatar Jun 28 '23 06:06 apexbb

same problem

ozalpozqur avatar Jul 06 '23 21:07 ozalpozqur

I have installed the npm i @radix-ui/[email protected]

but it still cannot reset the Select in Form Component,

Can anyone suggest a solution for me?

My Select Option cannot be null

@apexbb Are you resetting to ""? If so and still having issues, can you provide a minimal sandbox? Thansk!

joaom00 avatar Jul 06 '23 21:07 joaom00

Try using value instead of defaultValue

-<Select onValueChange={field.onChange} defaultValue={field.value}>
+<Select onValueChange={field.onChange} value={field.value}>

riyaadh-abrahams avatar Jul 12 '23 09:07 riyaadh-abrahams

Try using value instead of defaultValue


-<Select onValueChange={field.onChange} defaultValue={field.value}>

+<Select onValueChange={field.onChange} value={field.value}>

I have tried this and setting the defaultValues to undefined. When form.reset() is called, the <Select value={field.value}> doesn't reset back to the original where the <SelectValue placeholder='Select a role'>.

dejongyeong avatar Jul 29 '23 00:07 dejongyeong

Any movement on this? All of these suggestions don't work as expected. Just like @dejongyeong stated, if you have the default value declared as an empty string while passing the value prop the default placeholder gets overwritten by the empty string.

anricoj1 avatar Aug 25 '23 17:08 anricoj1

As a temporary workaround, I have modified the SelectTrigger to explicitly check the field.value. If it is not set, it displays your placeholder.

<FormItem>
  <FormLabel>Size</FormLabel>
  <Select
    onValueChange={field.onChange}
    defaultValue={field.value}
+   value={field.value}
  >
    <FormControl>
      <SelectTrigger>
+       {field.value ? <SelectValue placeholder="Select size" /> : "Select size"}
      </SelectTrigger>
    </FormControl>
    <SelectContent>
      <SelectGroup>
        <SelectLabel>Size</SelectLabel>
        <SelectItem value="small">
          Small
        </SelectItem>
        <SelectItem value="medium">
          Medium
        </SelectItem>
      </SelectGroup>
    </SelectContent>
  </Select>

You also need to add the value prop to the Select component, as @riyaadh-abrahams suggested, in order to clear the selection when calling form.reset().

w1am avatar Aug 25 '23 18:08 w1am

As @joaom00 said, you need to upgrade to @radix-ui/[email protected]. I got the desired behavior by setting the default value to "" and adding value={field.value} to the Select.

PieroGiovanni avatar Sep 01 '23 22:09 PieroGiovanni

To set the default value to "", we would have to allow it as a valid value in our schema right? In which case, how can we ensure that the empty string "" throws a validation error for the Select field?

sbhbenjamin avatar Sep 25 '23 08:09 sbhbenjamin

To set the default value to "", we would have to allow it as a valid value in our schema right? In which case, how can we ensure that the empty string "" throws a validation error for the Select field?

You can do something like z.string().trim().min(1, ( message: "required" }) for string values or .refine() for more complex cases

minhson3012 avatar Sep 27 '23 09:09 minhson3012

As @joaom00 said, you need to upgrade to @radix-ui/[email protected]. I got the desired behavior by setting the default value to "" and adding value={field.value} to the Select.

Thank you for this very simple yet effective fix.

adopstarliu avatar Jan 29 '24 12:01 adopstarliu

As a temporary workaround, I have modified the SelectTrigger to explicitly check the field.value. If it is not set, it displays your placeholder.

<FormItem>
  <FormLabel>Size</FormLabel>
  <Select
    onValueChange={field.onChange}
    defaultValue={field.value}
+   value={field.value}
  >
    <FormControl>
      <SelectTrigger>
+       {field.value ? <SelectValue placeholder="Select size" /> : "Select size"}
      </SelectTrigger>
    </FormControl>
    <SelectContent>
      <SelectGroup>
        <SelectLabel>Size</SelectLabel>
        <SelectItem value="small">
          Small
        </SelectItem>
        <SelectItem value="medium">
          Medium
        </SelectItem>
      </SelectGroup>
    </SelectContent>
  </Select>

You also need to add the value prop to the Select component, as @riyaadh-abrahams suggested, in order to clear the selection when calling form.reset().

The issue still not fix as of today and this workaround works for me. Thank you so much.

berlcamp avatar Feb 19 '24 23:02 berlcamp

Same issue. I need the select field to be empty by default but in zod it's required. I don't want to have a "not_selected" option or something.

WillsWebsites avatar Feb 27 '24 02:02 WillsWebsites

Anybody with a solution to this form reset issue?

sammykisina avatar Feb 29 '24 08:02 sammykisina

<FormField
  control={form.control}
  name='furniture'
  render={({ field }) => {
    return (
      <FormItem>
        <FormLabel>Nội thất</FormLabel>
        <Select
          onValueChange={(value) =>
            value && field.onChange(value)
          }
          value={field.value}
        >
          <FormControl>
            <SelectTrigger>
              <SelectValue />
            </SelectTrigger>
          </FormControl>
          <SelectContent>
            {Object.values(furniture).map((item) => (
              <SelectItem value={item.key} key={item.key}>
                {item.name}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </FormItem>
    )
  }}
/>

I found the problem caused by the onValueChange event inside the form. Try to modify onChangeValue and use value instead of defaultValue

buiquockhai avatar Mar 02 '24 09:03 buiquockhai

Would be great if this was fixed

danielvoelk avatar Mar 07 '24 06:03 danielvoelk

As a temporary workaround, I have modified the SelectTrigger to explicitly check the field.value. If it is not set, it displays your placeholder.

<FormItem>
  <FormLabel>Size</FormLabel>
  <Select
    onValueChange={field.onChange}
    defaultValue={field.value}
+   value={field.value}
  >
    <FormControl>
      <SelectTrigger>
+       {field.value ? <SelectValue placeholder="Select size" /> : "Select size"}
      </SelectTrigger>
    </FormControl>
    <SelectContent>
      <SelectGroup>
        <SelectLabel>Size</SelectLabel>
        <SelectItem value="small">
          Small
        </SelectItem>
        <SelectItem value="medium">
          Medium
        </SelectItem>
      </SelectGroup>
    </SelectContent>
  </Select>

You also need to add the value prop to the Select component, as @riyaadh-abrahams suggested, in order to clear the selection when calling form.reset().

Hi,

Is there any progress on this? I'm rendering my select values enforced by a nativeEnum by zod, which is dictated by a Prisma enum. I can only set the default value on the form as undefined, I cannot pass "" (empty string) as a default value.

The above workaround works in displaying the placeholder value, the only issue is that the previous value is still checked (Check Icon).

Is there anyway to remove the check at reset?

bcmendis avatar Mar 12 '24 09:03 bcmendis

As a temporary workaround, I have modified the SelectTrigger to explicitly check the field.value. If it is not set, it displays your placeholder.

<FormItem>
  <FormLabel>Size</FormLabel>
  <Select
    onValueChange={field.onChange}
    defaultValue={field.value}
+   value={field.value}
  >
    <FormControl>
      <SelectTrigger>
+       {field.value ? <SelectValue placeholder="Select size" /> : "Select size"}
      </SelectTrigger>
    </FormControl>
    <SelectContent>
      <SelectGroup>
        <SelectLabel>Size</SelectLabel>
        <SelectItem value="small">
          Small
        </SelectItem>
        <SelectItem value="medium">
          Medium
        </SelectItem>
      </SelectGroup>
    </SelectContent>
  </Select>

You also need to add the value prop to the Select component, as @riyaadh-abrahams suggested, in order to clear the selection when calling form.reset().

thank you so much ❤️

leandiazz avatar Mar 15 '24 21:03 leandiazz

react hook form reset has bug !

use form.reset, form can't rerender select. so u can see it not working. but form.setValue can working and rerender.

and how to use it for 100% working

just like this

reset single form item

const onReset = (name: string) => form.setValue(name, "");

reset all form item

import { useFormContext, UseFormReturn } from "react-hook-form";

export const useReset = (form?: UseFormReturn<any>) => {
  const formctx = useFormContext();
  const { getValues, setValue } = form ?? formctx;
  const fields = Object.keys(getValues());
  fields.forEach((field) => setValue(field, ""));
};

weipengzou avatar Mar 18 '24 06:03 weipengzou

Hi! I had the same issue but someone on Stackoverflow suggested I make this change, which seems to have worked for me.

https://stackoverflow.com/questions/69548100/react-hook-form-and-react-select-not-working-as-expected

<FormField
  control={form.control}
  name='furniture'
  render={({ field }) => {
    return (
      <FormItem>
        <FormLabel>Nội thất</FormLabel>
        <Select
-          onValueChange={(value) =>
-          value && field.onChange(value)
-          }
+         {...field}
        >
          <FormControl>
            <SelectTrigger>
              <SelectValue />
            </SelectTrigger>
          </FormControl>
          <SelectContent>
            {Object.values(furniture).map((item) => (
              <SelectItem value={item.key} key={item.key}>
                {item.name}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </FormItem>
    )
  }}
/>

MatiasSommer avatar Mar 21 '24 15:03 MatiasSommer

Hi! I had the same issue but someone on Stackoverflow suggested I make this change, which seems to have worked for me.

https://stackoverflow.com/questions/69548100/react-hook-form-and-react-select-not-working-as-expected

Hello! I tried it and it works. But now I have an error in the console browser: Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()? Check the render method of 'Controller'.

parmetra avatar Apr 04 '24 07:04 parmetra