Releases: edmundhung/conform
v1.15.1
What's Changed
- Added support for nullable constraints in
getZodConstraint(#1126) - Fixed
useControlnot reflecting the input's default value in the DOM (#1121) - Fixed
useControlnot dispatching a change event when callingcontrol.change()with the input's default value (#1122) - Fixed
parseWithZodandparseWithValibotincorrectly treating falsy result values as errors (#1115)
New Contributors
Full Changelog: v1.15.0...v1.15.1
v1.15.0
What's Changed
-
Added a getFieldValue helper to extract and validate field values from FormData or URLSearchParams. (#1112)
import { getFieldValue } from '@conform-to/react/future'; // Basic: returns `unknown` const email = getFieldValue(formData, 'email'); // With type guard: returns `string`, throws if not a string const name = getFieldValue(formData, 'name', { type: 'string' }); // File type: returns `File`, throws if not a File const avatar = getFieldValue(formData, 'avatar', { type: 'file' }); // Object type: parses nested fields into `{ city: unknown, ... }` const address = getFieldValue<Address>(formData, 'address', { type: 'object' }); // Array: returns `unknown[]` const tags = getFieldValue(formData, 'tags', { array: true }); // Array of objects: returns `Array<{ name: unknown, ... }>` const items = getFieldValue<Item[]>(formData, 'items', { type: 'object', array: true, }); // Optional: returns `string | undefined`, no error if missing const bio = getFieldValue(formData, 'bio', { type: 'string', optional: true });
It also infers types from the field name:
import { useForm, useFormData, getFieldValue } from '@conform-to/react/future'; function Example() { const { form, fields } = useForm(); // Retrieves the value of the `address` fieldset as an object, e.g. `{ city: unknown; ... }` const address = useFormData(form.id, (formData) => getFieldValue(formData, fields.address.name, { type: 'object' }), ); // ... }
Full Changelog: v1.14.1...v1.15.0
v1.14.1
What's Changed
- Relaxed the
FormConfigtype to allow bothlastResultandonSubmitto be optional (#1116)
Full Changelog: v1.14.0...v1.14.1
v1.14.0
Breaking Changes (Future APIs)
-
The
intendedValueoption in the report helper has been renamed tovalueand now works as thedefaultValuewhen resetting the form. Previously, this option was ignored when resetting and the form would always reset to the default value. You can now use thevalueoption to update or reset forms to a specific value. (#1079)// Update form to a specific value after submission return { result: report(submission, { value: updatedValue, }), }; // Reset form to a specific value after submission return { result: report(submission, { reset: true, value: defaultValue, }), };
-
parseSubmissionnow strips empty values by default. This makes it easier to work with schemas directly (withoutcoerceFormValue) since you no longer need extra validation like.min(1)for required fields. You can setstripEmptyValues: falseto preserve empty values if needed. (#1110)const formData = new FormData(); // Empty text input formData.append('name', ''); // Empty file input formData.append('files[]', new File([], '')); parseSubmission(formData); // { payload: {} } parseSubmission(formData, { stripEmptyValues: false }); // { payload: { name: '', files: [new File([], '')] } }
What's Changed
-
Schema-first future
useFormhook with improved type inference (#1106)The
schemaoption is now promoted to the first argument ofuseFormfor better type inference:// Before: schema in options const { form, fields } = useForm({ schema: mySchema, onSubmit(event, { value }) { // value type inference could be inconsistent }, }); // After: schema as first argument const { form, fields } = useForm(mySchema, { onSubmit(event, { value }) { // value is fully typed based on your schema }, });
onValidateis now required when not using a schemaEither(Relaxed the type to allow both to be optional in v1.14.1)onSubmitorlastResultmust be provided
The old API with
schemain options still works but is now deprecated. It will be removed in the next minor release. -
Fixed
parseSubmissionarray handling for entries ending with[]. Previously, when multiple form entries had the same name ending with[](e.g.,todos[]), all items were incorrectly pushed as a single nested array element. Now they are correctly spread as individual array items. (#1108)const formData = new FormData(); formData.append('todos[]', 'Buy milk'); formData.append('todos[]', 'Walk dog'); formData.append('todos[]', 'Write tests'); parseSubmission(formData); // Before (incorrect): { todos: [['Buy milk', 'Walk dog', 'Write tests']] } // After (correct): { todos: ['Buy milk', 'Walk dog', 'Write tests'] }
Improvements
- You can now import from
@conform-to/zod/v3if you need to work with v3 schema using zod v4. (Thanks @kesoji - #1090) - Fixed type inference for
getFieldset()with interface declarations (#1097) - Moved
lastResultlogic from an effect to the render phase. Your form component may now render twice within a single lifecycle when needed, but state updates that previously spanned two separate lifecycles now complete in one. (#1103) - Improved
FormOptionsandValidationAttributestypes compatibility withexactOptionalPropertyTypessetting in tsconfig. (#1105)
Full Changelog: v1.13.3...v1.14.0
v1.13.3
What's Changed
- Fixed Zod v4
.required()support with coerceFormValue by @chimame (#1084)
Full Changelog: v1.13.2...v1.13.3
v1.13.2
What's Changed
- Fix change detection to avoid triggering unnecessary change events when a File input or select value hasn't actually changed (#1078)
- Updated vitest and vitest/browser dependencies to latest versions by @chimame (#1077)
Full Changelog: v1.13.1...v1.13.2
v1.13.1
What's Changed
- Fixed a type regression with
DefaultValuethat prevented settingundefinedon required fields whenexactOptionalPropertyTypesis enabled. (#1072)
Full Changelog: v1.13.0...v1.13.1
v1.13.0
Breaking changes on future exports
The following metadata will no longer returns undefined to resolves behavior difference on React 18 and 19 with regards to the defaultValue property:
metadata.defaultValuenow returns an empty string''instead ofundefinedwhen no default value is set or the value cannot be serializedmetadata.defaultOptionsnow returns an empty array[]instead ofundefinedwhen no default options are set or the value cannot be serializedmetadata.defaultCheckednow explicitly returnsfalseinstead ofundefinedwhen the field value is not'on'
What's Changed
-
The
intent.reset()method now accepts an optionaldefaultValueparameter to reset forms to a different value (#1065)// Clear all fields <button type="button" onClick={() => intent.reset({ defaultValue: null })}> Clear </button> // Restore to a specific snapshot <button type="button" onClick={() => intent.reset({ defaultValue: savedValue })}> Restore </button>
Additionally,
intent.update()has been optimized to behave more consistently withintent.reset(), with improved type inference when updating form value by not specifying thenameoption. -
Added
formReftouseControlhook (#1059)The
useControlhook now exposes aformRefproperty that provides access to the form element associated with the registered input. This is particularly useful when usinguseControlwith other form-level hooks likeuseFormData()anduseIntent().const control = useControl({ defaultValue: '' }); // Dispatch intent with useIntent const intent = useIntent(control.formRef); // The formRef automatically stays in sync even if the form attribute changes <input ref={control.register} form="dynamic-form-id" />;
-
Fixed an issue with
coerceFormValuewidening the schema type toGenericSchema | GenericSchemaAsync. It now preserves the exact schema type with compatibility to the standard schema types. (#1060)
Full Changelog: v1.12.1...v1.13.0
v1.12.1
What's Changed
- Fixed an issue where React DevTools would throw an error when inspecting field metadata. The Proxy now handles symbol properties used by React internals gracefully. (#1062)
- Fixed
insertandupdateintent type inference when field shape cannot be inferred. (#1063)
Full Changelog: v1.12.0...v1.12.1
v1.12.0
What's changed
Metadata Customization
This update introduces a <FormOptionsProvider /> component under the future export. (#1047)
You can now define global form options, including custom metadata properties that match your form component types when integrating with UI libraries or any custom components.
import {
FormOptionsProvider,
type BaseMetadata,
} from '@conform-to/react/future';
import { TextField } from './components/TextField';
// Define custom metadata properties that matches the type of our custom form components
function defineCustomMetadata<FieldShape, ErrorShape>(
metadata: BaseMetadata<FieldShape, ErrorShape>,
) {
return {
get textFieldProps() {
return {
name: metadata.name,
defaultValue: metadata.defaultValue,
isInvalid: !metadata.valid,
} satisfies Partial<React.ComponentProps<typeof TextField>>;
},
};
}
// Extend the CustomMetadata interface with our implementation
// This makes the custom metadata types available on all field metadata objects
declare module '@conform-to/react/future' {
interface CustomMetadata<FieldShape, ErrorShape>
extends ReturnType<typeof defineCustomMetadata<FieldShape, ErrorShape>> {}
}
// Wrap your app with FormOptionsProvider
<FormOptionsProvider
shouldValidate="onBlur"
defineCustomMetadata={defineCustomMetadata}
>
<App />
</FormOptionsProvider>;
// Use custom metadata properties in your components
function Example() {
const { form, fields } = useForm({
// shouldValidate now defaults to "onBlur"
});
return (
<form {...form.props}>
<TextField {...fields.email.textFieldProps} />
</form>
);
}Additionally, you can now customize the base error shape globally using the CustomTypes interface:
declare module '@conform-to/react/future' {
interface CustomTypes {
errorShape: { message: string; code: string };
}
}This restricts the error shape expected from forms and improves type inference when using useField and useFormMetadata.
Improvements
- Added
ariaInvalidandariaDescribedByfield metadata (#1047) - Added Zod 4 prefault schema support (#1052) - Thanks @chimame!
- Improved docs layout setup (#1051) - Thanks @fiws!
- Fixed an issue with checkbox not being marked as touched on form submit with async validation (#1048)
- Fixed a bug with default values from Zod 3 default schema not being validated when coercion is enabled (#1050)
Full Changelog: v1.11.0...v1.12.0