feat: getFieldValue helper
This PR introduces a getFieldValue(formData, options) helper to retrieve a field value from FormData with optional type guards:
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 });
As it would be too complex to offer a type guard for object shape. All properties are mapped to the unknown type so you still get type hint when accessing individual properties. You can pass them to React and display the value just fine. Only if you have any specific logic based on the value, you will need to validate the property type yourself.
Here is a complete example:
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' }),
);
// ...
}
🦋 Changeset detected
Latest commit: 161a31ccc6a15d538b8ee4bb70b06ab9c0711b7d
The changes in this PR will be included in the next version bump.
This PR includes changesets to release 5 packages
| Name | Type |
|---|---|
| @conform-to/dom | Minor |
| @conform-to/react | Minor |
| @conform-to/valibot | Minor |
| @conform-to/yup | Minor |
| @conform-to/zod | Minor |
Not sure what this means? Click here to learn what changesets are.
Click here if you're a maintainer who wants to add another changeset to this PR
More templates
@conform-to/dom
npm i https://pkg.pr.new/@conform-to/dom@1112
@conform-to/react
npm i https://pkg.pr.new/@conform-to/react@1112
@conform-to/valibot
npm i https://pkg.pr.new/@conform-to/valibot@1112
@conform-to/validitystate
npm i https://pkg.pr.new/@conform-to/validitystate@1112
@conform-to/yup
npm i https://pkg.pr.new/@conform-to/yup@1112
@conform-to/zod
npm i https://pkg.pr.new/@conform-to/zod@1112
commit: 161a31c
Deploying conform with
Cloudflare Pages
| Latest commit: |
161a31c
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://3fdf54b1.conform.pages.dev |
| Branch Preview URL: | https://get-field-value.conform.pages.dev |
@oxc @jansedlon What do you think?
@edmundhung yes I think that could work
I like it, looks safe, covers many basic use cases, and the implementation still seems maintainable.
Instinctively I would say why not also add support for { type: "object", schema: standardSchema }, but that would certainly complicate things, and can be added rather simple as a custom helper.
Hi @edmundhung, thanks for maintaining Conform! We rely on the getFieldValue feature from this PR for our production use case. Any expected timeline for merge + release? Appreciate your work!
@foxlau Should be in a day or two.
Any feedback on this API? Happy to make some adjustments before landing it.
Released in v1.15.0.
Hi @edmundhung. Do we support boolean/number as a types ?
@andrew-shpak Not at the moment. It is tricky to support other types as not everyone uses the same format, e.g. you could have number inputs with thousand separators.
You can have a simple helper to parses it yourself, like this:
function parseNumber(value: unknown) {
if (!value) {
// If no value or value is an empty string
return null;
}
const num = parseFloat(value);
if (Number.isNaN(num)) {
throw new Error(`Expected number but received ${value}`);
}
return num;
}
// Usage:
const value = getFieldValue(formData, fields.something.name);
const number = parseNumber(value);
Thanks, I see