gform-react
Back to Guides

Initial Values

Seed a form's starting values with the value prop, async with onInit or fetch, and understand first-paint validation and the reset baseline.

Every field starts empty by default. To give a field a starting value, set the value prop on GInput - it's the initial value, not a controlled value, so the user (and dispatchChanges) can change it freely afterward:

<GInput formKey="name" value="Ada Lovelace" />

There are three ways to seed a form, depending on where the data comes from:

SourceUseWhen
A value you know at render timeThe value prop on GInputDefaults, "new" forms, constants
The whole form, loaded asynconInit on GFormEdit forms - load a record after mount
One field, loaded asyncThe fetch prop on GInputA field whose value depends on an API or other fields

The value prop is typed per field

The type of value matches the field's type, and so does the value you read back from state / toRawData():

<GInput formKey="name"   value="Ada" />          {/* string  */}
<GInput formKey="age"    type="number"   value={30} />     {/* number  */}
<GInput formKey="active" type="checkbox" value={true} />   {/* boolean */}

When you don't pass a value, the field falls back to a sensible per-type default - "" for text, 0 for number, false for checkbox, null for file. (For convenience the native defaultValue and checked attributes are accepted too, but value is the canonical way to seed.)

This works through the element render prop exactly the same way - the seeded value arrives in props.value (or props.checked), so you just spread it:

<GInput
  formKey="status"
  value="on-track"
  element={(input, props) => (
    <select {...props}>
      <option value="on-track">On track</option>
      <option value="ahead">Ahead</option>
    </select>
  )}
/>

Initial values are validated on first paint

A field that mounts with a value has its native constraints checked immediately, so an invalid starting value shows its error on the very first render - no interaction needed - and the form's native validity is synced so it can't be submitted while invalid:

const validators = {
  "*": new GValidator().withRequiredMessage("Required"),
  username: new GValidator(/* … */).withMinLengthMessage("At least 4 characters"),
};
 
// Renders already showing "At least 4 characters":
<GInput formKey="username" value="ab" minLength={4} />

A field that mounts empty stays pristine - error/touched are false until the user interacts with it (or you submit). So seeding an empty optional field costs nothing, and seeding a value you know is invalid surfaces the problem up front.

Custom validators wait for the mount effect

Only native constraints (required, minLength, pattern, type="email", …) are baked at registration for the first paint. Custom and async validators (withCustomValidation) run in the field's mount effect with the full field set, so a cross-field initial error appears a tick later.

Async initial values: edit forms

When the starting values come from an API, seed the whole form with onInit - it runs once after mount and merges the partial state you return. This is the standard "load a record to edit" pattern:

<GForm<ProfileForm>
  onInit={async () => {
    const profile = await fetchProfile();
    return {
      name: { value: profile.name },
      city: { value: profile.city },
    };
  }}
>

For a single field that loads on its own (or reloads when other fields change), use GInput's fetch prop instead. See GForm → onInit for the full onInit contract.

Initial values define the reset baseline

A form reset restores each field to its initial value - the value prop, or whatever onInit seeded (gform re-snapshots the baseline after onInit runs, so an edit form resets to the loaded record, not to empty). In other words, "initial" and "reset target" are the same thing.

Try it live

A mix of seeded fields - text, number, a checked checkbox, a select, and a username that starts invalid so you can see its error on first paint. The form is valid as soon as username is long enough:

Loading playground…

The Username field shows "At least 4 characters" immediately because it mounted with an invalid value; fix it and the Save button enables. Notice toRawData() already reflects every seeded value before you touch anything - the number stays a number and the checkbox a boolean.

See GForm for onInit, Fetching Data for the fetch prop, and Resetting a Form for how the initial values become the reset baseline.