Future APIs / useFormData

useFormData

The useFormData hook is part of Conform's future export. These APIs are experimental and may change in minor versions. Learn more

A React hook that subscribes to live form values and derives state from them. Unlike useForm, it updates on every input change (but re-renders only when the result changes). Use it for dirty checking, computed values, or conditional UI.

import { useFormData } from '@conform-to/react/future';

const result = useFormData(formRef, selector, options);

To detect form updates, the hook listens to:

  • Form events: input, focusout, submit, and reset
  • DOM mutations:
    • When inputs are mounted or unmounted
    • When the name, form, or data-conform attributes change

Manual changes to input values (e.g. input.value = 'foo') are not tracked unless they also trigger an event or update the data-conform attribute.

#Parameters

fromRef?: FormRef

A reference to the form to observe. You can pass either:

  • A ref object from useRef(), pointing to a form-associated element (e.g. <form>, <input>, <button>, etc.)
  • A string ID of a form element

selector?: (formData: FormData | URLSearchParams, lastResult?: Result) => Result

A function that derives a value from the current form data. It receives:

  • The current form data, which may be:
    • a URLSearchParams object if the acceptFiles option is not set or false
    • a FormData object if acceptFiles: true
  • The previously returned value (or undefined on first render)

The selector is only called when the form element is available. If the form is not available (e.g., on SSR or initial client render), the hook returns undefined without calling the selector.

The hook will re-run the selector whenever the form changes, and trigger a re-render only if the returned value is not deeply equal to the previous one.

options.acceptFiles?: boolean

Set to true to preserve file inputs and receive a FormData object in the selector. If omitted or false, the selector receives a URLSearchParams object, where all values are coerced to strings.

options.fallback?: Value

The fallback value to return when the form element is not available (e.g., on SSR or initial client render). If provided, the hook returns Value instead of Value | undefined.

#Returns

The value returned by your selector function. If the form element is not available:

  • Returns fallback if provided
  • Returns undefined otherwise

#Example

Derive a single field value

1const name = useFormData(formRef, (formData) => formData.get('name') ?? '', {
2  fallback: '',
3});
4
5return <p>Hello, {name || 'guest'}!</p>;

Compute a summary from multiple fields

1const total = useFormData(formRef, (formData) => {
2  const prices = ['itemA', 'itemB', 'itemC'];
3  return prices.reduce((sum, name) => {
4    const value = parseFloat(formData.get(name));
5    return sum + (isNaN(value) ? 0 : value);
6  }, 0);
7});
8
9return <p>Total: ${total?.toFixed(2) ?? 'n/a'}</p>;

Conditionally show a section based on the form data

1const isSubscribed = useFormData(
2  formRef,
3  (formData) => formData.get('subscribe') === 'on',
4  { fallback: false },
5);
6
7return (
8  <>
9    <label>
10      <input type="checkbox" name="subscribe" />
11      Subscribe to newsletter
12    </label>
13
14    {isSubscribed && <NewsletterPreferences />}
15  </>
16);

#Tips

You can use any form-related element as the reference

You don't need to pass a reference to the <form> element itself. The hook will resolve the associated form automatically, either by:

  • the form attribute (e.g. <button form="my-form">)
  • or by traversing up the DOM to find the closest <form> ancestor

For example, here's how you might disable an Add to Cart button if the item is already selected in the form:

1function AddToCartButton({ itemId }: { itemId: string }) {
2  const buttonRef = useRef<HTMLButtonElement>(null);
3  const isAdded = useFormData(
4    buttonRef,
5    (formData) => formData.getAll('items').includes(itemId),
6    { fallback: false },
7  );
8
9  return (
10    <button ref={buttonRef} disabled={isAdded}>
11      Add to Cart
12    </button>
13  );
14}