CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-final-form

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

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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;
}

docs

field-registration.md

form-actions.md

form-creation.md

index.md

state-management.md

utilities.md

validation.md

tile.json