Files
gruperly/.agents/skills/react-hook-form/references/formcfg-default-values.md
2026-09-04 16:49:24 -03:00

2.3 KiB

title, impact, impactDescription, tags
title impact impactDescription tags
Always Provide defaultValues for Form Initialization CRITICAL prevents uncontrolled-to-controlled input warnings and a reset() with nothing to restore formcfg, default-values, initialization, useForm

Always Provide defaultValues for Form Initialization

useForm<T>() with no defaultValues starts every field as undefined. Three things break at once: any controlled input flips from uncontrolled to controlled on first keystroke (React logs a warning and can lose the value), reset() with no arguments has no baseline to restore to, and isDirty/dirtyFields compare against nothing so the form reads as dirty the moment anything is touched. Provide the full shape up front, using empty strings rather than undefined.

Incorrect (no defaultValues — reset() has no baseline, inputs start uncontrolled):

function ProfileForm({ user }: { user: User }) {
  const { register, reset, handleSubmit } = useForm<ProfileFormValues>()

  useEffect(() => {
    reset(user)
  }, [user, reset])

  return (
    <form onSubmit={handleSubmit(saveProfile)}>
      <input {...register('firstName')} />
      <input {...register('lastName')} />
      <button type="button" onClick={() => reset()}>Discard changes</button>
    </form>
  )
}

Correct (explicit defaults — reset() restores them, isDirty is meaningful):

function ProfileForm({ user }: { user: User }) {
  const { register, reset, handleSubmit } = useForm<ProfileFormValues>({
    defaultValues: { firstName: '', lastName: '' },
  })

  useEffect(() => {
    reset(user)
  }, [user, reset])

  return (
    <form onSubmit={handleSubmit(saveProfile)}>
      <input {...register('firstName')} />
      <input {...register('lastName')} />
      <button type="button" onClick={() => reset()}>Discard changes</button>
    </form>
  )
}

When the defaults come from the server, pass them directly rather than defaulting-then-resetting — see formcfg-async-default-values. After a successful save, move the baseline with resetDefaultValues rather than reset (see formstate-reset-default-values).

Note: Avoid custom objects with prototype methods (Moment, Luxon) as defaultValues — RHF deep-clones them. Use plain objects or primitives.

Reference: useForm - defaultValues