gform-react

gform-react

A lightweight, dependency-free TypeScript React form library built for performance, validation, and clean form logic.

Why gform-react?

The whole point of gform-react is that it should feel closer to writing native forms than to configuring a library.

  • Tiny & no dependencies - ~4.8 KB gzipped, tree‑shakable
  • Minimal re-renders - updates only the fields that actually change
  • Native HTML constraint validation - full support for min, max, pattern, minLength, maxLength, required, and more
  • Schema validation via Standard Schema v1 - any library implementing the spec works out of the box (Zod, Valibot, ArkType, Yup, …); drive the whole form from one schema via GValidator.withSchema / withSchemaAsync, including object-level cross-field rules with zero runtime dependencies
  • Custom & async validation - add any rule via withCustomValidation, including asynchronous server-side checks with withCustomValidationAsync
  • Cross-field validation - re-validate a field when another changes (e.g. confirm-password) via validatorDeps
  • Deeply Nested Forms - structure forms however you like, structure forms however you like, split a big form into focused and reusable components
  • Dynamic fields - add or remove fields at runtime without losing state
  • Native <form> actions - fully supports browser‑level form submission, including action, method, and HTTP navigation, with no JavaScript required
  • Next.js Server Actions support - works seamlessly with Server Actions through standard <form> submissions, with no special adapters or client‑side wiring
  • Custom data on any input - attach arbitrary data to a field via dispatchChanges (option lists, loading flags, fetched metadata); it's kept in form state for your UI, separate from the submitted value
  • Accessibility‑friendly - automatically manages aria-required and aria-invalid
  • File inputs - type="file" stores the real File object (or File[] with multiple), not the C:\fakepath\... string
  • React Native support - the same API on web and mobile (via gform-react/native); no adapters, no separate mental model

A 30-second taste

import { GForm, GInput, GValidator, type GValidators } from "gform-react";
 
interface SignInForm {
  username: string;
  password: string;
}
 
const validators: GValidators<SignInForm> = {
  "*": new GValidator().withRequiredMessage("This field is required"),
};
 
export default function App() {
  return (
    <GForm<SignInForm>
      validators={validators}
      onSubmit={(state, e) => {
        e.preventDefault();
        console.log(state.toRawData());
      }}
    >
      {(state) => (
        <>
          <GInput
            formKey="username"
            required
            placeholder="username"
            element={(input, props) => (
              <label>
                <input {...props} />
                {input.error && <small>{input.errorText}</small>}
              </label>
            )}
          />
          <button disabled={state.isInvalid}>Sign in</button>
        </>
      )}
    </GForm>
  );
}
New here?

Head to Installation to install the package, read Core Concepts to understand GForm, GInput, and form state, then build Your First Form.

Where to go next

  • Installation - install the package and wire up peer dependencies.
  • Core Concepts - the typed interface, the validators object, and the GForm component.
  • Your First Form - build and run a small validated form in a few lines.
  • Validation - native constraints, custom messages, async, Yup/Zod.
  • API Reference - every export and the shared state types, with links to each guide.
  • Examples & Playground - live, editable forms you can run in the browser.