Formify Docs

Formify

A modern, TypeScript-first form library for React — everything Formik has, plus what Formik doesn't

Formify

A modern, TypeScript-first form library for React — everything Formik has, plus what Formik doesn't.

Formify is a drop-in upgrade over Formik with:

  • ✅ Full API parity with Formik — useForm, <Formify>, <Form>, <Field>, <FastField>, <ErrorMessage>, <FieldArray>, useField, useFormifyContext, connect, withFormify, getFieldProps, setFieldValue, validateForm, resetForm, Yup interop and more.
  • ✅ Config-driven validation schemas — declare validation as plain data: { email: { required: true, email: true } }. No boilerplate.
  • ✅ 35+ built-in validators — email, URL, phone, UUID, IP, credit card (Luhn), SSN, EIN, ZIP, domain, slug, ISBN, strong password, date, time, min/max length, ranges, oneOf, confirm (password match), and more — each with configurable messages.
  • ✅ Async validation built in — debounced, cancellable API checks (e.g. "username already taken") via uniqueCheck() or custom asyncValidate, with stale-response protection and per-field loading flags.
  • ✅ Plugin system — hook into the form lifecycle: normalize input, add validation rules, block submits, react to errors — plus ready-made plugins: autosavePlugin, honeypotPlugin, confirmDirtyPlugin, passwordStrengthPlugin, formatPlugin. Nothing Formik can do, that Formify can't.
  • ✅ Input normalization — trim, uppercase, lowercase, digits, alphanumeric or custom transforms applied as the user types.
  • ✅ Input formatters — SSN, EIN, ITIN/TIN masks, country-aware phone numbers (with/without extension), ZIP, credit card, currency, date, time — applied on change or on blur, all customizable.
  • ✅ Beyond Formik — per-field validateOnChange/validateOnBlur overrides, conditional validation (when), dependent-field revalidation (deps), focus-first-error on submit, global message dictionaries (i18n), debounce config.
  • ✅ TypeScript-first — full type safety and autocomplete, dual ESM + CJS builds, zero runtime dependencies (React peer only).

v1 → v2? The old useFormValidator(initialValues, schema, onSubmit) API and regexVal helpers still work — see Migration from v1.

Installation

npm install formify-js
# or
yarn add formify-js
# or
pnpm add formify-js

Requires react >= 18. Formify has zero runtime dependencies (React peer only).

Quick start

import { useForm, V } from "formify-js";

interface SignupValues {
  email: string;
  password: string;
}

export function Signup() {
  const form = useForm<SignupValues>({
    initialValues: { email: "", password: "" },
    validationSchema: {
      email: { required: true, email: true },
      password: { required: true, minLength: 8, strongPassword: true },
    },
    onSubmit: async (values) => {
      await api.signup(values);
    },
  });

  return (
    <form onSubmit={form.handleSubmit}>
      <input {...form.getFieldProps("email")} type="email" />
      {form.touched.email && form.errors.email && (
        <p className="error">{form.errors.email}</p>
      )}

      <input {...form.getFieldProps("password")} type="password" />
      {form.touched.password && form.errors.password && (
        <p className="error">{form.errors.password}</p>
      )}

      <button type="submit" disabled={form.isSubmitting}>
        {form.isSubmitting ? "Signing up…" : "Sign up"}
      </button>
    </form>
  );
}

Or with components (Formik-compatible API, Formify names):

import { Formify, Form, Field, ErrorMessage } from "formify-js";

<Formify
  initialValues={{ email: "", password: "" }}
  validationSchema={{
    email: { required: true, email: true },
    password: { required: true, minLength: 8 },
  }}
  onSubmit={async (values) => api.signup(values)}
>
  <Form>
    <Field name="email" type="email" placeholder="you@example.com" />
    <ErrorMessage name="email" component="p" />
    <Field name="password" type="password" />
    <ErrorMessage name="password" component="p" />
    <button type="submit">Sign up</button>
  </Form>
</Formify>

Async validation (unique checks)

import { useForm, uniqueCheck } from "formify-js";

const form = useForm({
  initialValues: { username: "" },
  validationSchema: {
    username: {
      required: true,
      minLength: 3,
      asyncValidate: uniqueCheck(
        async (value, { signal }) => {
          const res = await fetch(`/api/users/exists?username=${value}`, { signal });
          return res.json(); // true = taken
        },
        { message: "This username is already taken", debounce: 400 },
      ),
    },
  },
  onSubmit: (values) => api.createUser(values),
});

// Show a spinner while the check is running:
{form.validating.username && <Spinner />}

Stale responses are cancelled automatically via AbortSignal — typing "joh" then "john" only ever shows the result for "john".

Features at a glance

AreaFormikFormify
Hooks (useForm)✅✅ (plus extras)
Components (Formify, Form, Field, FastField, ErrorMessage, FieldArray)✅✅
HOC (withFormify, connect)✅✅
Yup schemas✅ (peer dep)✅ (duck-typed, optional)
Config-driven schemas❌✅
Built-in validators with messages❌✅ (35+)
Input formatters (SSN, EIN, phone, …)❌✅
Trim modes (start / end / both) on change or blur❌✅
Async validation with debounce + cancellation❌✅
Unique/API checks (uniqueCheck)❌✅
Input normalization❌✅
Plugin system❌✅
Conditional validation (when)❌✅
Dependent-field revalidation (deps)❌✅
Per-field validateOnChange / validateOnBlur❌✅
Focus first invalid field on submit❌✅
Global message dictionary (i18n)❌✅
TypeScript-first, dual ESM/CJSpartial✅

Test app

The repo ships a Vite test app that exercises every feature live — signup with async unique checks, formatters, plugins, FieldArray, conditional + i18n, Yup interop, and a performance benchmark (per-keystroke latency, full-form validation and submit cost at 10 / 50 / 100 / 250 fields).

cd app
npm install
npm run dev        # http://localhost:5173
npm run build      # production build

Documentation

On this page