v1.20.0
Breaking Changes (Future APIs)
Important
All options previously deprecated in the future APIs will be removed in the next minor release as we prepare for an upcoming v2.0 beta.
-
Renamed the
valuereturned byresolveSubmission()totargetValue. (#1246)-const { intent, value } = resolveSubmission(submission); +const { intent, targetValue } = resolveSubmission(submission);
-
Staged validation in
onValidate()now uses a{ result, pending }object instead of a tuple. (#1247)Staged validation lets
onValidate()return a known validation result immediately while a slower asynchronous check continues. This behavior was previously undocumented. If you relied on it, update your callback to use the new object structure:-return [result, pending]; +return { result, pending };
What's Changed
-
Added custom intents to the future APIs. Define an intent with
defineIntent(), register it throughconfigureForms()oruseForm(), and dispatch it alongside the built-in intents. (#1191)const copyField = defineIntent< (options: { from: string; to: string }) => void >({ parse(options) { return options; }, resolve({ value, payload }) { return setPathValue( value, payload.to, getPathValue(value, payload.from), ); }, }); const forms = configureForms({ intents: { copyField }, }); const { intent } = forms.useForm(); intent.copyField({ from: fields.billing.name, to: fields.shipping.name, });
This also adds
resolveSubmission()for resolving custom and built-in intents on the server. -
Added custom form state to the future APIs. Use
defineCustomState()to derive state from intents and submission results, then read it fromform.customState. (#1244)const submitCount = defineCustomState({ initialize() { return 0; }, handleIntent(count, { intent }) { return intent.type === 'submit' ? count + 1 : count; }, }); const { form } = useForm({ customState: { submitCount }, }); form.customState.submitCount;
-
The
valueoption fromreport()has also been deprecated in favor oftargetValuefor consistency. It will be removed in the next minor release. (#1247)report(submission, { - value, + targetValue, }); -
Improved the future Zod
getConstraints()API so fields required within a union or discriminated-union branch remain required. This better supports conditional forms where each branch renders its own fields. (#1236) -
Added support for
z.readonly()schemas incoerceFormValue()andgetZodConstraint(). The inner schema is now coerced correctly and its validation constraints are preserved across the default,/v3, and/v4exports. (#1239) -
Preserved empty string values inside array fields when building submission payloads, avoiding dropped or shifted entries. (#1233)
-
Preserved empty values in
defaultPayloadso custom controls can render their complete default structure before user interaction. (#1235) -
Preserved
lastResulterrors wheninitialValueis omitted. Passingnullremains the explicit reset behavior. (#1237) -
Fixed the default stable metadata types so schema-specific metadata remains assignable to
FormMetadataandFieldMetadatawithout explicitly providing a schema generic. (#1221) -
Improved
intent.update()types so extra properties are rejected when updating an array item by index. (#1245)
Documentation
- Fixed the
getInputPropsdocumentation. (#1227)
New Contributors
- @long-long-float made their first contribution in #1227
- @Subharup-31 made their first contribution in #1221
- @morgan-coded made their first contribution in #1233
- @artola made their first contribution in #1235
- @chatman-media made their first contribution in #1239
Full Changelog: v1.19.4...v1.20.0