Releases: edmundhung/conform
v1.7.0
What's changed
The future export and useControl hook
We’ve introduced the first API under the new future export: useControl.
The future export is a new entry point for previewing upcoming features that may evolve before being stabilized in a future major version. If you haven’t seen it yet, check out our announcement for context.
The first experimental API is useControl — a new hook that helps you integrate custom inputs with Conform. Compared to useInputControl, it offers a more flexible setup with better support for multi-select, file inputs, and checkbox groups.
We’ve documented it in detail:
- What's special with
useControl? - Updated integration guide
- Updated examples with a new one for React Aria Components
Give it a try — and let us know what you think!
New field metadata for default values
Field metadata now includes three new properties:
defaultValue(string | undefined)defaultChecked(boolean | undefined)defaultOptions(string[] | undefined)
const { fields } = useForm({
defaultValue: {
username: 'edmundhung',
tags: ['react', 'forms'],
subscribe: true,
}
});
fields.username.defaultValue; // 'edmundhung'
fields.tags.defaultOptions; // ['react', 'forms']
fields.subscribe.defaultChecked; // trueThese values are automatically derived from your form’s defaultValue, making it easier to connect each field with useControl and wire up individual input elements.
Full Changelog: v1.6.0...v1.7.0
v1.6.0
What's Changed
-
You can now use our Zod helpers with any Zod v4 schema by importing from the new module export
@conform-to/zod/v4:
import {
parseWithZod,
getZodConstraint,
} from '@conform-to/zod/v4';Special thanks to @chimame for championing this upgrade and making Zod v4 compatibility possible!
Full Changelog: v1.5.1...v1.6.0
v1.5.1
What's Changed
- fix:
useInputControl()should not return an array value whenform.update()is called with a single value (#935)
Full Changelog: v1.5.0...v1.5.1
v1.5.0
What's Changed
- feat(conform-zod): Set empty object when zodDiscriminatedUnion is specified. by @taku-hatano in #909
- feat(conform-zod): Add support auto type coercion with z.literal for boolean, number, and bigint by @elecdeer in #930
- feat(conform-valibot): Add support auto type coercion with literal for boolean, number, and bigint by @chimame in #931
- fix(conform-valibot): support nested fields with only checkboxes by @chimame in #911
- fix(conform-valibot): where
undefinedvalue could not be correctly verified whenarraywas defined innullishoroptionalschema by @chimame in #917 - fix(conform-valibot): re-support Valibot
config/fallbackmethods for piped primitive value schemas by @nanto in #925 - fix(conform-valibot): fix synchronize reference versions by @chimame in #932
Improvements
- Bumped
@conform-to/valibotpackage version to sync the with the rest of the packages in #929. - Added an installation guide in #918. Thanks @chimame
- Updated docs in #912, . Thanks @lhapaipai!
- Fixed an issue with the README file missing on the published packages in #927. Thanks @edmundhung
New Contributors
- @taku-hatano made their first contribution in #909
- @lhapaipai made their first contribution in #912
- @nanto made their first contribution in #925
- @elecdeer made their first contribution in #930
Full Changelog: v1.4.0...v1.5.0
v1.4.0
What's Changed
Form side effect
Previously, Conform heavily relied on the React key prop to update the input value when updating field values with form.update() or resetting the form with form.reset().This was not ideal and have introduced several issues along the way, such as the unexpected onBlur validation behavior caused by React re-mounting the input when the key prop changes and the new warning message with spreading key with getInputProps() in React 19.
In v1.4.0, Conform will run a side effect to update the input value instead. Meaning...
- Helpers like getInputProps, getSelectProps or getTextareaProps are no longer spreading a
keyto the input element. If you were seeing the messageWarning: A props object containing a "key" prop is being spread into JSX, it should be resolved now. - Outstanding issues caused by inputs being unmounted (e.g. #701 and #730) are now fixed
With the need of key props removed, Conform is now able to validate and update the input value as long as a name is provided:
function Example() {
const [form, fields] = useForm({
// ...
});
return (
<form id={form.id} onSubmit={form.onSubmit}>
<input type="text" name={fields.username.name} />
<input type="password" name={fields.password.name} />
<button>Submit</button>
</form>
);
}v1.3.0
Hello world! We're finally back after a bit of a break. This release is a bit small, but we hope it's the start of a more regular update schedule moving forward. I'm excited to share that @chimame has joined the team and is prepping our first valibot integration release in #876. We'll be sharing more details about the other changes as well. Thanks for your patience and stay tuned!
Custom coercion
v1.3.0 adds the ability to disable the default auto coercion behavior by setting the disableAutoCoercion option to true in parseWithZod in #871.
function Example() {
const [form, fields] = useForm({
onValidate({ formData }) {
return parseWithZod(formData, {
schema,
disableAutoCoercion: true,
});
},
});
// ...
}You can then manage how the form value is parsed yourself, or use the new unstable_coerceFormValue helper to coerce form value:
import { parseWithZod, unstable_coerceFormValue as coerceFormValue } from '@conform-to/zod';
import { z } from 'zod';
// Coerce the form value with default behaviour
const schema = coerceFormValue(
z.object({
// ...
})
);
// Coerce the form value with default coercion overrided
const schema = coerceFormValue(
z.object({
ref: z.number()
date: z.date(),
amount: z.number(),
confirm: z.boolean(),
}),
{
// Trim the value for all string-based fields
// e.g. `z.string()`, `z.number()` or `z.boolean()`
string: (value) => {
if (typeof value !== 'string') {
return value;
}
const result = value.trim();
// Treat it as `undefined` if the value is empty
if (result === '') {
return undefined;
}
return result;
},
// Override the default coercion with `z.number()`
number: (value) => {
// Pass the value as is if it's not a string
if (typeof value !== 'string') {
return value;
}
// Trim and remove commas before casting it to number
return Number(value.trim().replace(/,/g, ''));
},
// Disable coercion for `z.boolean()`
boolean: false,
},
);You can also customize coercion for a specific schema by setting the customize option.
import {
parseWithZod,
unstable_coerceFormValue as coerceFormValue,
} from '@conform-to/zod';
import { useForm } from '@conform-to/react';
import { z } from 'zod';
import { json } from './schema';
const metadata = z.object({
number: z.number(),
confirmed: z.boolean(),
});
const schema = coerceFormValue(
z.object({
ref: z.string(),
metadata,
}),
{
customize(type) {
// Customize how the `metadata` field value is coerced
if (type === metadata) {
return (value) => {
if (typeof value !== 'string') {
return value;
}
// Parse the value as JSON
return JSON.parse(value);
};
}
// Return `null` to keep the default behavior
return null;
},
},
);This helper is currently released with the unstable_ prefix to collect more feedbacks. Lock your version to the patch version range (e.g. ~1.3.0) if you want to use this feature without unexpected changes.
Other Improvements
- Added coercion support with branded types (e.g.
z.string().brand()) in #864. Thanks @krsilas! - Fixed CI issue with corepack in #860. Thanks @yukiomoto!
- Updated docs in #761, #785, #806, #859, #877, #880. Thanks @KirillSBarsukov, @suzukisan22, @AlexWebLab!
New Contributors
- @KirillSBarsukov made their first contribution in #761
- @suzukisan22 made their first contribution in #806
- @yukiomoto made their first contribution in #860
- @krsilas made their first contribution in #864
- @AlexWebLab made their first contribution in #877
Full Changelog: v1.2.2...v1.3.0
v1.2.2
What's Changed
fix: revert auto field value update (#778)
The auto field value update feature introduced in v1.2.0 has caused several critical issues with significant user impact. While I appreciate what they accomplished, I’ve realized the current solution isn't robust enough to handle all potential use cases. To minimize the impact on everyone, I believe it's best to revert these changes for now.
Full Changelog: v1.2.1...v1.2.2
v1.2.1
What's Changed
- Fixed an issue with Conform overwriting the value of input buttons in #766. In v1.2.0, if you have any input buttons rendered, their value will be likely rewritten to empty string as Conform treats it as normal inputs and tries to update its value based on the default value.
Full Changelog: v1.2.0...v1.2.1
v1.2.0
Embrace the platform
This change is reverted in v1.2.2
One of the most critical changes in this release is the auto field value update implemented in #729. Conform now updates input value using the DOM api instead of relying on the key to re-mount the inputs with the new defaultValue. It means:
- It is no longer required to pass the
key(e.g.fields.title.key) to the input elements unless you are rendering a list.
// Before: The minimum setup
<input key={field.title.key} name={fields.title.name} defaultValue={fields.title.defaultValue} />
// Now: the key props is no longer required
<input name={fields.title.name} defaultValue={fields.title.defaultValue} />
// Bonus: if the form is not rendered server side, or you don't mind the user experience before JS is loaded...
<input name={fields.title.name} />- Helpers like getInputProps, getSelectProps or getTextareaProps are no longer spreading a
keyto the input element. If you were seeing the messageWarning: A props object containing a "key" prop is being spread into JSX, it should be resolved now. - Outstanding issues caused by inputs being unmounted (e.g. #701 and #730) are now fixed
Pre-release
Thanks to pkg.pr.new, we are now releasing a preview version on every pull request (#742)
You will find a comment on the PR like this one from pkg.pr.new with each package name listed. If you expand the item, you will see a command to install the pre-release version. If you are not using pnpm, you can swap it with npm install, or just copy the package URL and replace the version in the package.json with it.
We are also shipping a pre-release version on every commit merged to main in the format https://pkg.pr.new/@conform-to/package@commit . For example, if you would like to install the pre-release version of @conform-to/dom and @conform-to/zod up to db63782, you can run:
npm install https://pkg.pr.new/@conform-to/dom@db63782
npm install https://pkg.pr.new/@conform-to/zod@db63782Other Improvements
- Improved the types of
submission.payloadin #706. If you were using Remix with single fetch, the action results should no longer be in typenever. Thanks @timvandam! - Fixed empty string default value support in #741. Previously, we suggested using
.default()to set a fallback value. However,.default()does not work as expected withz.string().default(''). This issue has now been resolved, but keep in mind that the default value is still subject to validation errors. For more predictable results, we recommend using.transform(value => value ?? defaultValue)instead. - Implement zod object coercion in #733. Conform should support nested fields with only checkboxes now.
- Added bigint coercion support with zod in #726. Thanks @lifeiscontent!
- Improved the types of the default value in #719. As
FormValueshould never benull. Thanks @aaronadamsCA! - Added a multiple select example with shadcn-ui in #753. Thanks @pwli0755!
- Improved the shadcn-ui Switch Component example to use
control.valuein #721. Thanks @reborn2135! - Fixed typo in
parseWithYup.mdandFormProvider.mdin #708, #751. Thanks @uttk, @felixyeboah! - Improved the ja docs messages in #709, #710, #711, #712. Thanks @k70suK3-k06a7ash1!
- Explained the usage of allErrors with checkbox group in #735.
New Contributors
- @reborn2135 made their first contribution in #721
- @uttk made their first contribution in #708
- @felixyeboah made their first contribution in #751
- @k70suK3-k06a7ash1 made their first contribution in #709
- @pwli0755 made their first contribution in #753
- @timvandam made their first contribution in #706
Full Changelog: v1.1.5...v1.2.0
v1.1.5
Improvements
- Fixed an issue with
unstable_useControlnot resetting the value of the registered input on form reset (#674)
Full Changelog: v1.1.4...v1.1.5