# react-final-form: subscription-based form state for React

> A thin React binding over the Final Form core, built on the observer pattern so only the fields you subscribe to re-render.

**final-form/react-final-form** — 🏁 High performance subscription-based form state management for React

- Repository: https://github.com/final-form/react-final-form
- Website: https://final-form.org/react
- Stars: 7,433 · Forks: 496
- Language: JavaScript
- License: MIT
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/final-form-react-final-form

## A binding over Final Form rather than a form library of its own

The most important structural fact is that this repository is not the state management library. It is a React wrapper around Final Form, which lives in a separate repository and does the actual work of holding form state, running validation and tracking which fields have been touched. The README states this plainly and links across, which makes the division of labour easy to reason about: the core is framework-agnostic and testable on its own, and the React package is the part that knows about components.

That split shows in the package metadata. `package.json` names only React and Final Form as peers, and the published artefact is a set of built files:

```json
"main": "dist/react-final-form.cjs.js",
"module": "dist/react-final-form.es.js",
"typings": "dist/index.d.ts",
```

A CommonJS entry, an ES module entry and TypeScript declarations, with a `files` array containing nothing but `dist`. The build runs through Rollup with Babel, Terser for minification and separate CommonJS and JSON plugins, which is the conventional modern setup and explains the range of devDependencies in the same file.

## Why the subscription model is the actual design decision

Form libraries tend to re-render more than a form needs. Every keystroke changes state, and a naive binding pushes that state through the tree, so a twenty-field form can redraw on each character in one field. react-final-form's answer is the Observer pattern: you ask for the slice of state a component needs, and only that component updates.

The README describes this as opt-in subscriptions, phrased as only updating on the state you need, and puts the resulting bundle size at 3 kB gzipped with a link to bundlephobia. Those two claims belong together. Subscriptions are what keep the update cost bounded, and a small footprint is what keeps adding the library to a bundle painless.

For a reader coming from Formik or React Hook Form, the practical difference is where the reactive boundary sits. Hooks-based approaches tend to give you a hook per field and let React's own reconciler do the work. This library hands you render props and subscriptions, which is more verbose per field but puts you in control of exactly which components depend on which values. Neither is automatically better; they fail differently when a form grows.

## The v7 release replaced Flow with TypeScript

Version 7.0.0, published in June 2025, converted the library from Flow to TypeScript. The release notes are unusually candid about the versioning: there should be no breaking changes, but because so much code was touched, the author bumped to a major version out of precaution.

The preview build ahead of it, v7.0.0-0, shows what came along: the TypeScript migration itself, React 19 added to peer dependencies, and a run of dependabot bumps for transitive build tooling such as axios, qs, json5 and follow-redirects. React 19 landing in peer dependencies alongside a type rewrite is the combination most likely to shake out type errors in consumer code, which is presumably why the notes warn about TypeScript-specific breaking changes.

The v7.0.1 patch in May 2026 is a better guide to what the rewrite cost. It is a list of bug fixes with no breaking changes, and several are recognisably TypeScript-migration casualties: `useField` returning the form's `initialValues` instead of the field's own initial value on first render, a `select` with `multiple` not defaulting to an empty array, and the `destroyOnUnregister` option losing initial values in StrictMode. There is also a genuine logic fix where checkbox and radio `checked` handling was using `format` where it should have used `parse`.

## The examples directory does the documentation's job

The README is short. Beyond the feature list and the sponsorship note, it is a set of links: Getting Started, a v6 to v7 migration guide, Philosophy, Examples, API and FAQ, all pointing at final-form.org rather than at files in the repository.

That leaves the `examples/` directory as the place to actually read the library. The listing is close to a catalogue of form problems, and the naming is precise enough to search by symptom. Validation is split across `field-level-validation/`, `async-field-level-validation/`, `debounced-record-level-validation/` and `hybrid-sync-async-record-level-validation/`, which is the clearest sign that this project treats sync and async validation as one system with two speeds rather than two features.

The rest of the list covers the things that usually get hand-rolled: `field-arrays/` for dynamic fields, `calculated-fields/`, `conditional-fields/`, `focus-first-error/`, `auto-save-field-blur/`, `auto-save-with-debounce/` and `auto-save-selective-debounce/`. Typeahead appears twice, once with downshift and once with Redux behind it, and there is a `credit-card/` example for formatting patterns. If you want to know whether a specific requirement is supported, searching this directory is faster than reading the API page.

## Maintenance signals, including the ones that contradict each other

The repository is active. The last push was on 2026-05-30, v7.0.1 shipped on 2026-05-05, and the project is MIT licensed with 7436 stars and 496 forks. Erik Rasmussen is named as the author in `package.json`, and the repository is explicitly sponsored by Sencha, which shows up in the README as a banner rather than as a feature.

Against that, the issue tracker has 378 open issues on a repository of this size, which is high enough to be worth reading before you adopt. The README also carries a feedback survey link, which suggests the maintainer is looking for signal on direction.

The tree contains some artefacts that outlived their purpose. There is a `.flowconfig` and a `tslint.json` next to `tsconfig.json` and `eslint.config.mjs`, so at least two linting generations are represented at once, and the badges still point at Travis CI while the build configuration is Rollup and Babel. None of that is a functional problem, but it is a fair signal that the repository's housekeeping trails the library itself.

## Conclusion

react-final-form is a small, opinionated layer that does one thing: bind a subscriptions-based core to React components. The claim of zero bundle-affecting dependencies and a 3 kB gzipped footprint is backed by a `package.json` whose only runtime peers are React and Final Form, and the subscription model is a real answer to the re-render problem rather than a marketing line. What the README does not do is teach the library, so the `examples/` directory is where the actual documentation lives, roughly two dozen runnable cases covering async validation, field arrays and calculated fields. If you are picking between this and a hooks-first library, the deciding question is whether render-prop components and a subscription-first mental model fit your team.

## FAQ

### What is the best form library for React?

It depends on how you want reactivity to work. react-final-form is a thin binding over a subscriptions-based core, so components re-render only for the state they subscribed to, and it costs about 3 kB gzipped with no runtime dependencies beyond React and Final Form. Hooks-first libraries read more idiomatically in function components; this one gives you finer control over render frequency at the price of render props.

### How can I create dynamic forms in React?

With react-final-form, dynamic field sets are handled by the FieldArray pattern rather than by hand-written state, and the repository ships a field-arrays example you can read. Related cases such as conditional-fields and calculated-fields have their own examples in the same directory, which makes it a reasonable place to check whether your requirement is covered.

### What is the difference between react-final-form and final-form?

final-form is the framework-agnostic core that owns form state, validation and submission. react-final-form is the React binding around it, published separately and listing Final Form as a peer dependency, so the state logic can be tested without React and reused in other environments.

## Sources

- [final-form/react-final-form on GitHub](https://github.com/final-form/react-final-form)
- [License: MIT](https://github.com/final-form/react-final-form/blob/main/LICENSE)
- [Project website](https://final-form.org/react)
- [README](https://github.com/final-form/react-final-form/blob/main/README.md)
- [Releases](https://github.com/final-form/react-final-form/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/final-form-react-final-form
