conform icon indicating copy to clipboard operation
conform copied to clipboard

feat: getFieldValue helper

Open edmundhung opened this issue 4 months ago • 7 comments

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' }),
  );

  // ...
}

edmundhung avatar Dec 02 '25 00:12 edmundhung

🦋 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

changeset-bot[bot] avatar Dec 02 '25 00:12 changeset-bot[bot]

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

pkg-pr-new[bot] avatar Dec 02 '25 00:12 pkg-pr-new[bot]

Deploying conform with  Cloudflare Pages  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

View logs

@oxc @jansedlon What do you think?

edmundhung avatar Dec 02 '25 21:12 edmundhung

@edmundhung yes I think that could work

jansedlon avatar Dec 03 '25 07:12 jansedlon

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.

oxc avatar Dec 03 '25 07:12 oxc

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 avatar Dec 09 '25 06:12 foxlau

@foxlau Should be in a day or two.

Any feedback on this API? Happy to make some adjustments before landing it.

edmundhung avatar Dec 09 '25 11:12 edmundhung

Released in v1.15.0.

edmundhung avatar Dec 10 '25 00:12 edmundhung

Hi @edmundhung. Do we support boolean/number as a types ?

andrew-shpak avatar Dec 13 '25 13:12 andrew-shpak

@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);

edmundhung avatar Dec 13 '25 14:12 edmundhung

Thanks, I see

andrew-shpak avatar Dec 13 '25 15:12 andrew-shpak