gform-react
Back to Guides

Reading Form State

Turn form state into a plain object, FormData, or URLSearchParams with toRawData, toFormData, and toURLSearchParams.

When a form submits, you need its values in some concrete shape - a JSON object for an API, a FormData for a multipart upload, or a query string for a GET request. The form state gives you three methods for exactly that, all on the same state object you receive in onSubmit (and from the render prop):

MethodReturnsReach for it when…
state.toRawData()a plain object { [formKey]: value }sending JSON to an API, or building a domain object. Keeps native types (File, number, boolean).
state.toFormData()a FormData instancemultipart uploads or file fields, and Next.js Server Actions. Web only.
state.toURLSearchParams()a URLSearchParams instancea GET request or a shareable/bookmarkable query string.

All three take the same options object, so once you know one you know all three:

{
  include?: (keyof T)[];                       // only these fields (others dropped)
  exclude?: (keyof T)[];                       // drop these fields
  transform?: { [key in keyof T]?: (value) => any }; // map a value before it's written
}

include wins over exclude if you pass both, and transform runs on top of whichever set remains.

toRawData - a plain object

The default way to read the form. Values keep their JavaScript types, so a number field is a number and a checkbox is a boolean - no parsing needed. Spread it to add fields the form doesn't own:

onSubmit
onSubmit={(state, e) => {
  e.preventDefault();
  const payload = { ...state.toRawData(), createdAt: Date.now() };
  await fetch("/api/goals", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  });
}}

toFormData - multipart & files

toFormData() builds a FormData from the rendered <form>, keyed by each field's formKey. Because it reads the real DOM form, file inputs come through as actual File objects - which is what you want for uploads. Use it for multipart/form-data requests and Next.js Server Actions:

onSubmit
onSubmit={async (state, e) => {
  e.preventDefault();
  await fetch("/api/upload", { method: "POST", body: state.toFormData() });
  // don't set Content-Type - the browser sets the multipart boundary for you
}}
Web only

toFormData() depends on a native <form> element, so it's not available on React Native. RNGFormState exposes toRawData() and toURLSearchParams() instead - see React Native. For Server Actions you usually submit via the action prop rather than calling toFormData() yourself - see Server Actions.

toURLSearchParams - query strings

toURLSearchParams() is built from toRawData() and then handed to new URLSearchParams(...), so every value is stringified (42"42", true"true"). That makes it perfect for a GET search/filter form whose state should live in the URL - shareable and bookmarkable - and a poor fit for files (a File won't serialize to anything useful). Call .toString() for the query string:

onSubmit
onSubmit={(state, e) => {
  e.preventDefault();
  const params = state.toURLSearchParams();
  router.push(`/search?${params.toString()}`); // /search?q=shoes&size=42&inStock=true
}}

Shaping the output with options

include, exclude, and transform work the same across all three methods. Drop a field, keep only a few, or rewrite a value on the way out:

// Only two fields
state.toRawData({ include: ["email", "name"] });
 
// Everything except internal fields
state.toFormData({ exclude: ["_csrf"] });
 
// Map values before serializing
state.toURLSearchParams({
  transform: {
    q: (value) => value.trim().toLowerCase(),
    tags: (value) => value.join(","),
  },
});

See all three side by side

This form renders each representation live as you type, so you can watch how the same state turns into an object, FormData, and a query string - and how types are preserved or stringified:

Loading playground…

Type in the fields and toggle the checkbox: in toRawData() the age stays a number and the checkbox a boolean, while toURLSearchParams() shows them as strings.

Why the checkbox is missing from toFormData()

toRawData() and toURLSearchParams() read field state, so an unchecked box is newsletter: false. toFormData() reads the native <form>, and the browser omits unchecked checkboxes from FormData entirely - so the key simply isn't there until it's checked. That's standard FormData behavior, worth knowing if your backend expects the key to always be present.

See GForm for the form component and Core Concepts for the full state reference.