Skip to content

[react-form] there is no way to clear a form value if it has a default value. #1289

Closed

Description

@a-eid

Describe the bug

useForm({
  defaultValues: {
    status: params.get('status') // assume this is active for example 
  }
})
      <form.Field name="status" asyncAlways>
        {(field) => (
        .... 
        field.setValue(undefined) // doesn't work. it resets status to active.
        form.setFieldValue("status", undefined) // doesn't work. it resets status to active.
        field.setValue(undefined) // doesn't work. it resets status to active.
        )}
      </form.Field> 

they all default to the default value

Your minimal, reproducible example

TODO

Steps to reproduce

N/A

Expected behavior

I would expect that setValue / handleChange would accept undefiend and it wouldn't be overridden by the default value.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

  • OS: Macos
  • version: ^1.0.5

TanStack Form adapter

None

TanStack Form version

^1.0.5

TypeScript version

No response

Additional context

No response

Activity

  1. vitassuper commented on Mar 17, 2025

    @vitassuper

    Consider to use null instead of undefined.

  2. LastGunslinger commented on Mar 19, 2025

    @LastGunslinger

    @vitassuper I'm currently using v1.1.0 and also having this problem. In this case I do think that is is a bug, or if not, then it should probably be expressly spelled out in the docs that this is not supported. For example, I if I have a type like this:

    type Exmaple = {
        first: string | undefined
        last: string | undefined
    }

    Where undefined is a valid value for one of the fields, and I set up a form with useForm:

    const form = useForm({
        defaultValues: { first: 'John', last: 'Smith' } as Example,
       // useForm options
    })

    then I would think that undefined is a valid value for either field. But in the form itself, if I do something like this:

    <form.Field name='first'>
        <CustomInput
            // Line below has unexpected behavior if value is undefined, and does not raise a type error because undefined IS a valid value
            onChange(value => field.handleChange(value))
        />
    </form.Field>
    field.handleChange(undefined)

    Instead of setting the value of that field to undefined, it will instead be reverted to 'John'. This seems like a bug to me, especially since it is typed correctly, and other form libraries that I've used in the past have not had issues with this. While agree that using null instead of undefined is probably a better choice, this conflicts with a lot of form validation that my company uses with Zod's partial() property, which is usually where the undefined values are coming from. Unfortunately Zod does not have a good way currently of making all of an object's fields null-ish (null or undefined) , so for now the partial function is the best that we can do.

  3. a-eid commented on Mar 20, 2025

    @a-eid
    Author

    Consider to use null instead of undefined.

    unfortunately neither null nor undefined work.

  4. LastGunslinger commented on Mar 20, 2025

    @LastGunslinger

    In my case, using null does work, but it required a refactor of my validation schemas to get there.

  5. a-eid commented on Mar 20, 2025

    @a-eid
    Author

    @LastGunslinger what changes did you make, my form element is optional and should acception undefined values. ?

  6. LastGunslinger commented on Mar 23, 2025

    @LastGunslinger

    @a-eid I ended up changing the type of the defaultValues property in the useForm hook, from something like this:

    type User {
        firstName?: string | undefined
        lastName?: string | undefined
    }

    to something like this:

    type User {
        firstName?: string | null | undefined
        lastName?: string | null | undefined
    }

    Then I just made sure that all of my field.handleChange calls used null instead of undefined when called:

    <CustomInput
        // {...otherProps}
        onChange={(value: string | null | undefined) => field.handleChange(value ?? null)}
    />

    After making these changes I don't have the issue anymore, but it did require a substantial change for my project. My actual defaultValues type is not so simple, it's defined as Zod schema based on a larger type, but the idea for fixing it is the same.

  7. jashworth commented on Apr 10, 2025

    @jashworth

    This seems like a bug to me, especially since it is typed correctly, and other form libraries that I've used in the past have not had issues with this.

    field.handleChanged(undefined);
    field.setValue(undefined);
    form.setFieldValue("AField", undefined);
    form.setFieldValue("AFieldContainingAnOptionalProp", { }); // prop is set to default value, NOT omitted
    

    The fact that all these can result in the field being set to something other than undefined seems counterintuitive and likely to lead to some ugly workarounds. (I outline one here.)

    Is the rationale behind this behaviour explained anywhere?

  8. Dogfalo commented on Apr 16, 2025

    @Dogfalo

    I would agree with this, setting undefined and resetting a value to default should be separated. I ended up having to set values to null and then filter them out at the end

  9. germanski commented on Apr 18, 2025

    @germanski

    I agree. Unpredictable behavior. Still, this is not a reset of the value. You also have to bypass through null. Waiting for correction

  10. Daniel88dev commented on May 11, 2025

    @Daniel88dev

    I have same issue, need to make one of the values null, or undefined when changing different value. But there seems to be no way, how to set value to null.

  11. obinna-okechukwu-01 commented on Jul 20, 2025

    @obinna-okechukwu-01

    I also notice this for arrays, and it's not clear how to fix this when removing an item in an array that has been defined in default values. For example:

    useForm({
      defaultValues: {
        users: [
          { id: 1, name: "John" },
          { id: 2, name: "Mary" }
       ]
      }
    })
    ...
    const users = useStore(form.store, (state) => state.values.users);
    const handleDeleteUser = (index: number) => {
          const user = users[index];
          if (!user) return;
          form.removeFieldValue("users", index); // doesn't work. The item momentarily gets removed from the list and then gets re-added.
    };
    
  12. gwansikk commented on Aug 10, 2025

    @gwansikk

    https://tanstack.com/form/latest/docs/framework/react/examples/array

    With a simple example, in the official docs’ Interactive Sandbox, after updating it with the code below (index.tsx):

    1. Delete the first Row.
    2. Click the “Add person” button.

    You’ll see a similar issue. I expected a new row, but when it’s undefined, the existing default value is shown instead.

    Example code
    import * as React from 'react';
    import { createRoot } from 'react-dom/client';
    import { useForm } from '@tanstack/react-form';
    
    interface Person {
      name: string | undefined;
    }
    
    const defaultPeople: { people: Array<Person> } = { people: [{ name: 'gwansikk'}] };
    
    function App() {
      const form = useForm({
        defaultValues: defaultPeople,
        onSubmit({ value }) {
          alert(JSON.stringify(value));
        },
      });
    
      return (
        <div>
          <form
            onSubmit={(e) => {
              e.preventDefault();
              e.stopPropagation();
              form.handleSubmit();
            }}
          >
            <form.Field name="people" mode="array">
              {(field) => {
                return (
                  <div>
                    {field.state.value.map((_, i) => {
                      return (
                        <form.Field key={i} name={`people[${i}].name`}>
                          {(subField) => {
                            return (
                              <div>
                                <label>
                                  <div>Name for person {i}</div>
                                  <input
                                    value={subField.state.value}
                                    onChange={(e) =>
                                      subField.handleChange(e.target.value)
                                    }
                                  />
                                  <button
                                    type="button"
                                    onClick={() => {
                                      field.removeValue(i);
                                    }}
                                  >
                                    X
                                  </button>
                                </label>
                              </div>
                            );
                          }}
                        </form.Field>
                      );
                    })}
                    <button
                      onClick={() => field.pushValue({ name: undefined })}
                      type="button"
                    >
                      Add person
                    </button>
                  </div>
                );
              }}
            </form.Field>
            <form.Subscribe
              selector={(state) => [state.canSubmit, state.isSubmitting]}
              children={([canSubmit, isSubmitting]) => (
                <button type="submit" disabled={!canSubmit}>
                  {isSubmitting ? '...' : 'Submit'}
                </button>
              )}
            />
          </form>
        </div>
      );
    }
    
    const rootElement = document.getElementById('root')!;
    
    createRoot(rootElement).render(
      <React.StrictMode>
        <App />
      </React.StrictMode>
    );
  13. alexkatz commented on Aug 26, 2025

    @alexkatz
    Contributor

    I'm also running into this issue. I need to clear a form field, but setting undefined causes the form's initial value to reappear instead.

    I've also resorted to using null, but it's creating a headache with Zod elsewhere in my codebase, where I need to replace optional() with nullish() in many places, which is undesirable and causes Typescript errors to ripple through other areas that aren't expecting null as a type.

    An alternative is to strip null fields manually, but that's another headache of hunting down all the places where form state is extracted and used elsewhere, and is a constant game of whack-a-mole.

    Resetting vs. setting a value of undefined should be separate and distinct actions, IMO.

  14. gwansikk commented on Sep 2, 2025

    @gwansikk

    I'm also running into this issue. I need to clear a form field, but setting undefined causes the form's initial value to reappear instead.

    I've also resorted to using null, but it's creating a headache with Zod elsewhere in my codebase, where I need to replace optional() with nullish() in many places, which is undesirable and causes Typescript errors to ripple through other areas that aren't expecting null as a type.

    An alternative is to strip null fields manually, but that's another headache of hunting down all the places where form state is extracted and used elsewhere, and is a constant game of whack-a-mole.

    Resetting vs. setting a value of undefined should be separate and distinct actions, IMO.

    I agree. I want to contribute to resolving this. It occurs not only in React Form but also in other library adapters.

  15. tictoc-kyle commented on Sep 12, 2025

    @tictoc-kyle

    I'm also having issues with this. My current hacky workaround is to set all default values to null, then use setFieldValue on mount. This way, I can call resetField to clear both the state and any errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions