Disabling Submit
Gate the submit button on state.isInvalid - the single source of truth for form validity.
Use state.isInvalid to disable your submit button. It's the single source of truth for
whole-form validity - no manual per-field value checks.
The pattern
Take the function child to access state, then bind disabled:
<GForm<SignInForm> validators={validators} onSubmit={handleSubmit}>
{(state) => (
<>
<GInput formKey="email" required type="email" element={/* … */} />
<GInput formKey="password" required minLength={8} element={/* … */} />
<button disabled={state.isInvalid}>Sign in</button>
</>
)}
</GForm>state.isValid is also available if you prefer the positive form.
Avoid manual value checks
Don't reconstruct validity by hand - it duplicates logic, misses async/custom rules, and drifts out of sync:
// ❌ Don't do this
<button disabled={!state.email?.value || !state.password?.value}>Sign in</button>
// ✅ Do this
<button disabled={state.isInvalid}>Sign in</button>state.isInvalid reflects native constraints, custom rules, and async validators. A hand-rolled
check based on value can't see any of those, so it will let invalid forms through (or block valid
ones).
Pending state during async work
While async validators run (debounced), the form is treated as invalid, so state.isInvalid is
true and the button stays disabled until the check resolves. Combine it with your own pending flag
for submit-time work:
{(state) => (
<button disabled={state.isInvalid || submitting}>
{submitting ? "Saving…" : "Save"}
</button>
)}No submit button?
If your form has no type="submit" control (e.g. you submit programmatically), onSubmit won't
fire on its own. Call state.checkValidity() before acting:
if (state.checkValidity()) {
save(state.toRawData());
}In development, gform warns in the console if a GForm has no submit button - a reminder that
onSubmit won't fire unless you submit manually.