or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

field-registration.mdform-actions.mdform-creation.mdindex.mdstate-management.mdutilities.mdvalidation.md
tile.json

tessl/npm-final-form

Framework-agnostic, high-performance form state management library with subscription-based updates.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/final-form@5.0.x

To install, run

npx @tessl/cli install tessl/npm-final-form@5.0.0

index.mddocs/

Final Form

Final Form is a framework-agnostic, high-performance form state management library that uses subscription-based updates to minimize re-renders and optimize performance. It provides zero dependencies and a small bundle size (5.1k gzipped), making it ideal for building forms in any JavaScript framework or vanilla JS application.

Package Information

  • Package Name: final-form
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install final-form

Core Imports

import { 
  createForm, 
  FORM_ERROR, 
  ARRAY_ERROR,
  getIn,
  setIn,
  formSubscriptionItems,
  fieldSubscriptionItems,
  configOptions,
  version
} from "final-form";

For CommonJS:

const { 
  createForm, 
  FORM_ERROR, 
  ARRAY_ERROR,
  getIn,
  setIn,
  formSubscriptionItems,
  fieldSubscriptionItems,
  configOptions,
  version
} = require("final-form");

Basic Usage

import { createForm } from "final-form";

// Create a form instance
const form = createForm({
  onSubmit: (values) => {
    console.log("Form submitted:", values);
  },
  initialValues: {
    firstName: "",
    lastName: "",
    email: "",
  },
});

// Register a field and subscribe to its state
const unsubscribe = form.registerField(
  "firstName",
  (fieldState) => {
    console.log("First name state:", fieldState);
  },
  { value: true, error: true, touched: true }
);

// Change field value
form.change("firstName", "John");

// Subscribe to form state
const unsubscribeForm = form.subscribe(
  (formState) => {
    console.log("Form state:", formState);
  },
  { values: true, errors: true, dirty: true }
);

Architecture

Final Form is built around several key architectural principles:

  • Subscription-Based Updates: Components only re-render when specific form/field state they care about changes
  • Framework Agnostic: Pure JavaScript core that can be integrated with any UI framework
  • Immutable State: All state updates are immutable, ensuring predictable behavior
  • Field-Level Subscriptions: Subscribe to individual fields to minimize unnecessary updates
  • Validation System: Support for both synchronous and asynchronous validation at form and field levels
  • Mutator Pattern: Extensible system for custom form state modifications

Capabilities

Form Creation

Core form creation functionality for initializing form instances with configuration and lifecycle management.

function createForm<FormValues, InitialFormValues>(
  config: Config<FormValues, InitialFormValues>
): FormApi<FormValues, InitialFormValues>;

interface Config<FormValues, InitialFormValues> {
  onSubmit: (
    values: FormValues,
    form: FormApi<FormValues, InitialFormValues>,
    callback?: (errors?: SubmissionErrors) => void
  ) => SubmissionErrors | Promise<SubmissionErrors> | void;
  debug?: DebugFunction<FormValues, InitialFormValues>;
  destroyOnUnregister?: boolean;
  initialValues?: InitialFormValues;
  keepDirtyOnReinitialize?: boolean;
  mutators?: { [key: string]: Mutator<FormValues, InitialFormValues> };
  validate?: (values: FormValues) => ValidationErrors | Promise<ValidationErrors>;
  validateOnBlur?: boolean;
  callbackScheduler?: (callback: () => void) => void;
}

Form Creation

State Management

Form and field state management with subscription-based updates for optimal performance.

interface FormApi<FormValues, InitialFormValues> {
  getState(): FormState<FormValues, InitialFormValues>;
  subscribe(
    subscriber: FormSubscriber<FormValues, InitialFormValues>,
    subscription: FormSubscription
  ): Unsubscribe;
  subscribeFormState(
    onChange: () => void,
    subscription: FormSubscription
  ): Unsubscribe;
  getFormSnapshot(): FormState<FormValues, InitialFormValues>;
  batch(fn: () => void): void;
  getRegisteredFields(): string[];
  pauseValidation(): void;
  resumeValidation(): void;
  isValidationPaused(): boolean;
  setConfig<K extends ConfigKey>(
    name: K,
    value: Config<FormValues, InitialFormValues>[K]
  ): void;
  setCallbackScheduler(scheduler?: (callback: () => void) => void): void;
}

interface FormState<FormValues, InitialFormValues> {
  active?: keyof FormValues;
  dirty?: boolean;
  dirtyFields?: { [key: string]: boolean };
  dirtyFieldsSinceLastSubmit?: { [key: string]: boolean };
  dirtySinceLastSubmit?: boolean;
  error?: any;
  errors?: ValidationErrors;
  hasSubmitErrors?: boolean;
  hasValidationErrors?: boolean;
  initialValues?: InitialFormValues;
  invalid?: boolean;
  modified?: { [key: string]: boolean };
  modifiedSinceLastSubmit?: boolean;
  pristine?: boolean;
  submitError?: any;
  submitErrors?: SubmissionErrors;
  submitFailed?: boolean;
  submitSucceeded?: boolean;
  submitting?: boolean;
  touched?: { [key: string]: boolean };
  valid?: boolean;
  validating?: boolean;
  values?: FormValues;
  visited?: { [key: string]: boolean };
}

State Management

Field Registration

Field registration and management system for dynamic form field handling with subscription capabilities.

interface FormApi<FormValues, InitialFormValues> {
  registerField: RegisterField<FormValues>;
  getFieldState<F extends keyof FormValues>(
    field: F
  ): FieldState<FormValues[F]> | undefined;
  subscribeFieldState<F extends keyof FormValues>(
    name: F,
    onChange: () => void,
    subscription: FieldSubscription
  ): Unsubscribe;
  getFieldSnapshot<F extends keyof FormValues>(
    name: F
  ): FieldState<FormValues[F]> | undefined;
  getRegisteredFields(): string[];
}

type RegisterField<FormValues> = <F extends keyof FormValues>(
  name: F,
  subscriber: FieldSubscriber<FormValues[F]>,
  subscription: FieldSubscription,
  config?: FieldConfig<FormValues[F]>
) => Unsubscribe;

Field Registration

Validation

Comprehensive validation system supporting both synchronous and asynchronous validation at form and field levels.

interface Config<FormValues, InitialFormValues> {
  validate?: (values: FormValues) => ValidationErrors | Promise<ValidationErrors>;
  validateOnBlur?: boolean;
}

interface FieldConfig<FieldValue> {
  getValidator?: GetFieldValidator<FieldValue>;
  validateFields?: string[];
  async?: boolean;
}

type FieldValidator<FieldValue> = (
  value: FieldValue,
  allValues: object,
  meta?: FieldState<FieldValue>
) => any | Promise<any>;

Validation

Form Actions

Form action methods for programmatic form manipulation including field changes, focus management, and form lifecycle.

interface FormApi<FormValues, InitialFormValues> {
  change<F extends keyof FormValues>(name: F, value?: FormValues[F]): void;
  blur(name: keyof FormValues): void;
  focus(name: keyof FormValues): void;
  initialize(
    data: InitialFormValues | ((values: FormValues) => InitialFormValues)
  ): void;
  reset(initialValues?: InitialFormValues): void;
  restart(initialValues?: InitialFormValues): void;
  resetFieldState(name: keyof FormValues): void;
  submit(): Promise<FormValues | undefined> | undefined;
}

Form Actions

Utilities

Utility functions and constants for deep object manipulation and form state management.

function getIn(state: object, complexKey: string): any;
function setIn(
  state: object,
  key: string,
  value: any,
  destroyArrays?: boolean
): object;

const FORM_ERROR: string;
const ARRAY_ERROR: string;
const formSubscriptionItems: readonly string[];
const fieldSubscriptionItems: readonly string[];
const configOptions: ConfigKey[];
const version: string;

Utilities

Types

interface FormSubscription {
  active?: boolean;
  dirty?: boolean;
  dirtyFields?: boolean;
  dirtyFieldsSinceLastSubmit?: boolean;
  dirtySinceLastSubmit?: boolean;
  modifiedSinceLastSubmit?: boolean;
  error?: boolean;
  errors?: boolean;
  hasSubmitErrors?: boolean;
  hasValidationErrors?: boolean;
  initialValues?: boolean;
  invalid?: boolean;
  modified?: boolean;
  pristine?: boolean;
  submitError?: boolean;
  submitErrors?: boolean;
  submitFailed?: boolean;
  submitting?: boolean;
  submitSucceeded?: boolean;
  touched?: boolean;
  valid?: boolean;
  validating?: boolean;
  values?: boolean;
  visited?: boolean;
}

interface FieldSubscription {
  active?: boolean;
  data?: boolean;
  dirty?: boolean;
  dirtySinceLastSubmit?: boolean;
  error?: boolean;
  initial?: boolean;
  invalid?: boolean;
  length?: boolean;
  modified?: boolean;
  modifiedSinceLastSubmit?: boolean;
  pristine?: boolean;
  submitError?: boolean;
  submitFailed?: boolean;
  submitSucceeded?: boolean;
  submitting?: boolean;
  touched?: boolean;
  valid?: boolean;
  validating?: boolean;
  value?: boolean;
  visited?: boolean;
}

interface FieldState<FieldValue> {
  active?: boolean;
  blur: () => void;
  change: (value: FieldValue | undefined) => void;
  data?: AnyObject;
  dirty?: boolean;
  dirtySinceLastSubmit?: boolean;
  error?: any;
  focus: () => void;
  initial?: FieldValue;
  invalid?: boolean;
  length?: number;
  modified?: boolean;
  modifiedSinceLastSubmit?: boolean;
  name: string;
  pristine?: boolean;
  submitError?: any;
  submitFailed?: boolean;
  submitSucceeded?: boolean;
  submitting?: boolean;
  touched?: boolean;
  valid?: boolean;
  validating?: boolean;
  value?: FieldValue;
  visited?: boolean;
}

type Unsubscribe = () => void;
type FieldSubscriber<FieldValue> = (state: FieldState<FieldValue>) => void;
type FormSubscriber<FormValues, InitialFormValues> = (
  state: FormState<FormValues, InitialFormValues>
) => void;
type ValidationErrors = AnyObject | undefined;
type SubmissionErrors = AnyObject | undefined;
type AnyObject = { [key: string]: any };
type IsEqual = (a: any, b: any) => boolean;

type ConfigKey = 
  | "debug"
  | "destroyOnUnregister"
  | "initialValues"
  | "keepDirtyOnReinitialize"
  | "mutators"
  | "onSubmit"
  | "validate"
  | "validateOnBlur"
  | "callbackScheduler";

type DebugFunction<FormValues, InitialFormValues> = (
  state: FormState<FormValues, InitialFormValues>,
  fieldStates: { [key: string]: FieldState<any> }
) => void;

type Mutator<FormValues, InitialFormValues> = (
  args: any[],
  state: MutableState<FormValues, InitialFormValues>,
  tools: Tools<FormValues, InitialFormValues>
) => any;

type GetFieldValidator<FieldValue = any> = () => FieldValidator<FieldValue> | undefined;

interface FieldConfig<FieldValue = any> {
  afterSubmit?: () => void;
  beforeSubmit?: () => void | false;
  data?: any;
  defaultValue?: any;
  getValidator?: GetFieldValidator<FieldValue>;
  initialValue?: any;
  isEqual?: IsEqual;
  silent?: boolean;
  validateFields?: string[];
  async?: boolean;
}

interface MutableState<FormValues, InitialFormValues> {
  fieldSubscribers: { [key: string]: Subscribers<FieldState<any>> };
  fields: { [key: string]: InternalFieldState<any> };
  formState: InternalFormState<FormValues>;
  lastFormState?: FormState<FormValues, InitialFormValues>;
}

interface Tools<FormValues, InitialFormValues> {
  changeValue: ChangeValue<FormValues, InitialFormValues>;
  getIn: GetIn;
  renameField: RenameField<FormValues, InitialFormValues>;
  resetFieldState: (name: string) => void;
  setIn: SetIn;
  shallowEqual: IsEqual;
}

type ChangeValue<FormValues, InitialFormValues> = (
  state: MutableState<FormValues, InitialFormValues>,
  name: string,
  mutate: (value: any) => any
) => void;

type RenameField<FormValues, InitialFormValues> = (
  state: MutableState<FormValues, InitialFormValues>,
  from: string,
  to: string
) => void;

type GetIn = (state: object, complexKey: string) => any;
type SetIn = (state: object, key: string, value: any, destroyArrays?: boolean) => object;

type Subscribers<T extends Object> = {
  index: number;
  entries: {
    [key: number]: {
      subscriber: Subscriber<T>;
      subscription: Subscription;
      notified: boolean;
    };
  };
};

type Subscription = { [key: string]: boolean | undefined };
type Subscriber<V> = (value: V) => void;

interface InternalFieldState<FieldValue = any> {
  active: boolean;
  afterSubmit?: () => void;
  beforeSubmit?: () => void | false;
  blur: () => void;
  change: (value: any) => void;
  data: AnyObject;
  focus: () => void;
  isEqual: IsEqual;
  lastFieldState?: FieldState<FieldValue>;
  length?: any;
  modified: boolean;
  modifiedSinceLastSubmit: boolean;
  name: string;
  touched: boolean;
  validateFields?: string[];
  validators: { [index: number]: GetFieldValidator<FieldValue> };
  valid: boolean;
  validating: boolean;
  visited: boolean;
}

interface InternalFormState<FormValues = Record<string, any>> {
  active?: string;
  asyncErrors: AnyObject;
  dirtySinceLastSubmit: boolean;
  modifiedSinceLastSubmit: boolean;
  error?: any;
  errors: ValidationErrors;
  initialValues?: AnyObject;
  lastSubmittedValues?: AnyObject;
  pristine: boolean;
  resetWhileSubmitting: boolean;
  submitError?: any;
  submitErrors?: AnyObject;
  submitFailed: boolean;
  submitSucceeded: boolean;
  submitting: boolean;
  valid: boolean;
  validating: number;
  values: FormValues;
}