Overview
Feature matrix
| Kin Form | React Hook Form | Formik | TanStack Form | |
|---|---|---|---|---|
| Zero dependencies | ✅ | ✅ | ❌ | ⚠️ |
| Framework-agnostic core | ✅ | ❌ | ❌ | ✅ |
| Type-safe nested field paths | ✅ | ✅ | ❌ | ✅ |
| Standard Schema support | ⚠️ | ⚠️ | ❌ | ✅ |
| Nested groups/arrays as first-class nodes | ✅ | ⚠️ | ⚠️ | ✅ |
| Selective re-rendering | ✅ | ✅ | ⚠️ | ✅ |
| Built-in async-validation debounce | ✅ | ❌ | ❌ | ✅ |
| Declarative cross-field revalidation | ✅ | ⚠️ | ❌ | ✅ |
✅ full support · ⚠️ partial or conditional · ❌ not supported
Bundle Size
React usage, minified + gzipped, same toolchain for every library.
Every library above is measured directly with the same toolchain — rolldown and its own built-in minifier, then gzip. That's not the same as Bundlephobia, which minifies with terser by default and can produce different sizes for the same source. Reproducible via deno task --cwd scripts bundle-size.
Performance
Smaller is better.
Initial mount (84 fields)
Flat field update burst (800x)
Nested field update burst (800x)
Array swap burst (800x, cycling adjacent pairs)
Array insert/remove burst (800x)
Flat field update burst + sync validator (800x)
Debounced async validation (800 updates, 50ms debounce)
Whole-form zod schema validation (on submit)
Untouched sibling re-renders (800 updates)
Flat field update burst (800x)
Nested field update burst (800x)
These are wall-clock numbers from one shared ~84-field form (flat fields, a nested group, an array) in a real (Happy DOM) React tree, reproducible via deno task --cwd scripts speed-bench.
The benchmark also counts re-renders per scenario — how many untouched sibling fields re-render when one field updates, charted above for the two scenarios where that count is clean and isolated.