shadcn Input + Form + Zod "A component is changing an uncontrolled input to be controlled"

IdoBa

a little background

Im using shadcn ui library and Zod to create some simple forms in my Next.js React app. The input are of type select and text

The problem

I'm following shadcn documentation on how to set up the form with Zod and shadcn's ui components but I get an error when the value of the text input is changing:

Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen.

Worth mentioning

The error only occurs when changing the text(username) input value.

also, the form is working properly despite the error.

What I've tried

Ive looked up the error and I found answers saying to add a value or defaultValue after the the {...field} with a combination of a useState('') hook, which solved the error but now it wont let me submit the form.

Code

'use client'
import {
    Form,
    FormControl,
    FormDescription,
    FormField,
    FormItem,
    FormLabel,
    FormMessage,
  } from "@/components/ui/form"
import { useForm } from 'react-hook-form'
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"
import { toast } from "@/components/ui/use-toast"
import Link from "next/link"
import { Input } from "@/components/ui/input"
import { ReactNode, useState } from "react"
const FormSchema = z.object({
  email: z
    .string({
      required_error: "Please select an email to display.",
    })
    .email(),
    username: z.string(),
 
})

const ZodForm = () => {

  const form = useForm<z.infer<typeof FormSchema>>({
    resolver: zodResolver(FormSchema),
  })
  
  function onSubmit(data: z.infer<typeof FormSchema>) {
    console.log(data);
    
    toast({
      title: "You submitted the following values:",
      description: (
        <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
          <code className="text-white">{JSON.stringify(data, null, 2)}</code>
        </pre>
      ),
    })
  }


  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="w-2/3 space-y-6">
        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <Select onValueChange={field.onChange} defaultValue={field.value}>
                <FormControl>
                  <SelectTrigger>
                    <SelectValue placeholder="Select a verified email to display" />
                  </SelectTrigger>
                </FormControl>
                <SelectContent>
                  <SelectItem value="[email protected]">[email protected]</SelectItem>
                  <SelectItem value="[email protected]">[email protected]</SelectItem>
                  <SelectItem value="[email protected]">[email protected]</SelectItem>
                </SelectContent>
              </Select>
              <FormDescription>
                You can manage email addresses in your{" "}
                <Link href="/examples/forms">email settings</Link>.
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <FormField
          control={form.control}
          name={'username'}
          render={({ field }) => (
            <FormItem>
              <FormLabel>Username</FormLabel>
              <FormControl>
                <Input placeholder="shadcn" {...field}  />
              </FormControl>
              <FormDescription>
                This is your public display name.
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        <button type="submit">Submit</button>
      </form>
    </Form>
  )
}

export default ZodForm
Ahmed Abdelbaset

That occurs because you didn't set defaultValues to useForm.

So, the defaultValues is undefined.

then When You use the <FormField /> You probably write it like this:

<FormField
  control={form.control}
  name="username"
  render={({ field }) => (
    <FormItem>
      <FormLabel>Username</FormLabel>
      <FormControl>
        <Input {...field} />
      </FormControl>
      <FormDescription>This is your public display name.</FormDescription>
      <FormMessage />
    </FormItem>
  )}
/>

Notice this line <Input {...field} />

The field is an object of ref, value, onChange, onBlur, and name.

The problem is the value is initialized by undefined then when you write any letter It's changed from undefined to string.

You can easily solve that by setting the default values

useForm({
  defaultValues: {
    username: ""
  }
})

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

TOP Ranking

HotTag

Archive