gform-react
Dependency-free · TypeScript · <tree-shakable

React forms built for performance and validation

A lightweight React form library with minimal re-renders, native + async validation, Yup/Zod support, Next.js Server Actions, and React Native - all with clean, type-safe form logic.

$npm i gform-react
SignIn.tsx

Isolate re-renders

gform-react keeps each field's state in an external store, so a keystroke only re-renders the field that changed. Type in both inputs and watch the render counters - the sibling components stay put on the left, but re-render on every keystroke on the right.

gform-react

0 re-renders
Child Component A0 re-renders
Child Component B0 re-renders
Child Component C0 re-renders

Field state lives in an external store. Only the active field re-renders - the siblings stay at 0.

VS

Controlled form (useState)

0 re-renders
Child Component A0 re-renders
Child Component B0 re-renders
Child Component C0 re-renders

Lifting the value into useState re-renders the parent - and every child with it, on each keystroke.

Subscriptions

Subscribe to individual input and form-state updates without re-rendering the whole form. Type on the left and toggle subscribers on the right - only the ones that are watching re-render and mirror the value live.

One source of truth

waiting…
Not subscribed
waiting…
Not subscribed

Each subscriber calls useFormSelector to read just the value it cares about.

Optimized event handling

With optimized, gform registers change, blur, and invalid just once on the <form> and routes each event to the right field. Type in any field, then flip the toggle - same behavior, far fewer handlers.

optimized is becoming the default in a future release

<form>
delegated →onChangeonBluronInvalid
onChangeonBluronInvalid
onChangeonBluronInvalid
onChangeonBluronInvalid
onChangeonBluronInvalid
onChangeonBluronInvalid
onChangeonBluronInvalid
onChangeonBluronInvalid
onChangeonBluronInvalid
Submit with the * fields empty to fire onInvalid.
3event listeners
3 events · once on the <form>

Deeply nested forms

A GInput doesn't have to be a direct child of GForm. Split a big form into focused and reusable components, nest them as deep as you like - every field joins the same form state, with zero prop drilling. Type at any depth and watch the single state update.

<CheckoutForm />form root
<ShippingSection />1 level deep
<AddressFields />2 levels deep
<ZipField />3 levels deep
state.toRawData()
{
"email": "",
"city": "",
"street": "",
"zip": ""
}

One form state, assembled from four components.

Fetching data

Populate a field from your API with fetch, and refetch when another field changes with fetchDeps. Pick a country - the city list reloads for it, debounced and cancel-safe.

city depends on country - one-way, no feedback loop.

CityField.tsx
// re-runs whenever country changes
<GInput
  formKey="city"
  fetchDeps={["country"]}
  fetch={async (input, fields) => {
    const cities = await loadCities(fields.country.value);
    return { options: cities, value: cities[0] };
  }}
  element={renderCity}
/>

Dynamic fields

Add and remove GInputs at runtime - each registers by its formKey, so the rest of the form keeps its values. Add a few, fill them in, then remove one from the middle.

Send invites to0 recipients

Dispatching changes

Write into the form yourself - seed values, surface a server error, or attach custom data to a field. Every change merges into state instead of replacing it.

Autofill sets both fields in one form-level call. Tag attaches a custom badge key that never reaches the submitted data. Clear + validate empties a field and re-runs its rule, so the error surfaces.

Lightweight by design

The entire library - forms, validation, selectors - ships in 4.5 kB gzipped. A fraction of the size of the alternatives, with no extra packages to install.

gform-reactv3.3.04.5 kB
react-final-formv7.0.1 · incl. final-form10.7 kB2.4× larger
react-hook-formv7.80.012.4 kB2.8× larger
formikv2.4.9 · incl. its dependencies14.6 kB3.2× larger

gzip size of each library's official production bundle, measured automatically from unpkg · react-final-form includes its required final-form package · formik shown with its runtime dependencies bundled (it ships no self-contained production file)

Everything you need to build forms

Powerful features without the bloat - gform-react stays out of your way.

Minimal re-renders

Only the fields that actually change update - not the whole form.

Lightweight & tree-shakable

Dependency-free. Import only what you use to keep bundles small.

Native constraint validation

Full support for required, min, max, pattern, minLength, maxLength, and more.

Custom & async validation

Add any rules, including asynchronous server-side checks.

Yup, Zod & more

Plug in any validation library you already use.

Deeply nested forms

Structure forms however you like, across any number of components.

Dynamic fields

Add or remove fields at runtime without losing state.

Next.js Server Actions

Works with native <form> actions - no special adapters or client wiring.

Accessible by default

Automatically manages aria-required and aria-invalid.

Real file inputs

type="file" stores the real File object, not the C:\fakepath string.

React Native support

Works seamlessly across web and mobile via gform-react/native.

Type-safe

Typed state, toRawData(), and validators from a single form interface.

Ready to build better forms?

Install gform-react and ship type-safe, performant forms in minutes.

$npm i gform-react
Read the docs →