Initial Values
Seed a form with onInit (sync or async) or the per-field value prop, and understand how initial values define the reset baseline.
Every field starts empty by default. There are two ways to give a form starting values - seed the
whole form at once with onInit, or set a starting value on each GInput. Whichever you
use, those initial values also become the form's reset baseline.
| Source | Use | When |
|---|---|---|
| The whole form | onInit on GForm | Edit forms, or any seed computed in one place - sync or async |
| One field | The value prop on GInput | Defaults and constants you know at render time |
| One field, loaded async | The fetch prop on GInput | A field whose value depends on an API or other fields |
Seed the whole form with onInit
onInit(state) runs once, right after the form mounts. Return a partial form and gform merges it
into the fields. It can be synchronous - return the partial directly when you already have the
data:
<GForm<ProfileForm>
onInit={() => ({
name: { value: "Ada Lovelace" },
city: { value: "London" },
})}
>…or asynchronous - return a Promise to load a record after mount. 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 contract.
Set a starting value per field with value
For a value you know at render time, 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" />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>
)}
/>Per-field 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.
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.
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:
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.