CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-final-form

High performance subscription-based form state management for React

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

field.mddocs/

Field Component

Individual field components with subscription-based state management, validation, formatting, and parsing capabilities.

Capabilities

Field Component

React component for individual form fields that connects to form state and provides input props and field metadata.

/**
 * Form field component with subscription-based state management
 * @param props - Field configuration and render props
 * @returns React element for the field
 */
const Field: <
  FieldValue = any,
  T extends HTMLElement = HTMLElement,
  FormValues = Record<string, any>
>(
  props: FieldProps<FieldValue, T, FormValues>
) => React.ReactElement;

interface FieldProps<
  FieldValue = any,
  T extends HTMLElement = HTMLElement,
  FormValues = Record<string, any>
> extends UseFieldConfig,
    Omit<RenderableProps<FieldRenderProps<FieldValue, T>>, "children"> {
  /** Field name (required) */
  name: string;
  /** Render function or React node */
  children?: RenderableProps<FieldRenderProps<FieldValue, T>>["children"];
  /** Additional HTML element props */
  [key: string]: any;
}

interface FieldRenderProps<
  FieldValue = any,
  T extends HTMLElement = HTMLElement,
  FormValues = any
> {
  /** Input props to spread on form elements */
  input: FieldInputProps<FieldValue, T>;
  /** Field metadata and state information */
  meta: FieldMeta;
}

interface FieldInputProps<
  FieldValue = any,
  T extends HTMLElement = HTMLElement
> {
  /** Field name */
  name: string;
  /** Blur event handler */
  onBlur: (event?: React.FocusEvent<T>) => void;
  /** Change event handler */
  onChange: (event: React.ChangeEvent<T> | any) => void;
  /** Focus event handler */
  onFocus: (event?: React.FocusEvent<T>) => void;
  /** Current field value */
  value: FieldValue;
  /** Checkbox/radio checked state */
  checked?: boolean;
  /** Multiple selection support */
  multiple?: boolean;
  /** Input type attribute */
  type?: string;
}

interface FieldMeta {
  /** Whether field is currently focused */
  active?: boolean;
  /** Custom field data */
  data?: Record<string, any>;
  /** Whether field value differs from initial */
  dirty?: boolean;
  /** Whether field is dirty since last submit */
  dirtySinceLastSubmit?: boolean;
  /** Current field validation error */
  error?: any;
  /** Initial field value */
  initial?: any;
  /** Whether field has validation errors */
  invalid?: boolean;
  /** Array length for array fields */
  length?: number;
  /** Whether field was ever modified */
  modified?: boolean;
  /** Whether field was modified since last submit */
  modifiedSinceLastSubmit?: boolean;
  /** Whether field value equals initial value */
  pristine?: boolean;
  /** Submission error for this field */
  submitError?: any;
  /** Whether last submission failed */
  submitFailed?: boolean;
  /** Whether last submission succeeded */
  submitSucceeded?: boolean;
  /** Whether form is currently submitting */
  submitting?: boolean;
  /** Whether field was ever focused */
  touched?: boolean;
  /** Whether field passes validation */
  valid?: boolean;
  /** Whether field is currently being validated */
  validating?: boolean;
  /** Whether field was ever visited (focused then blurred) */
  visited?: boolean;
}

Usage Examples:

import React from "react";
import { Form, Field } from "react-final-form";

// Basic text input field
function BasicField() {
  return (
    <Field name="firstName">
      {({ input, meta }) => (
        <div>
          <label>First Name</label>
          <input {...input} type="text" placeholder="First Name" />
          {meta.error && meta.touched && <span>{meta.error}</span>}
        </div>
      )}
    </Field>
  );
}

// Field with validation
function ValidatedField() {
  const required = (value: any) => (value ? undefined : "Required");

  return (
    <Field name="email" validate={required}>
      {({ input, meta }) => (
        <div>
          <label>Email</label>
          <input {...input} type="email" placeholder="Email" />
          {meta.error && meta.touched && (
            <span className="error">{meta.error}</span>
          )}
          {meta.validating && <span>Validating...</span>}
        </div>
      )}
    </Field>
  );
}

// Select field
function SelectField() {
  return (
    <Field name="country">
      {({ input, meta }) => (
        <div>
          <label>Country</label>
          <select {...input}>
            <option value="">Select a country</option>
            <option value="us">United States</option>
            <option value="uk">United Kingdom</option>
            <option value="ca">Canada</option>
          </select>
          {meta.error && meta.touched && <span>{meta.error}</span>}
        </div>
      )}
    </Field>
  );
}

// Checkbox field
function CheckboxField() {
  return (
    <Field name="subscribe" type="checkbox">
      {({ input, meta }) => (
        <div>
          <label>
            <input {...input} type="checkbox" />
            Subscribe to newsletter
          </label>
        </div>
      )}
    </Field>
  );
}

Field Configuration

Fields support extensive configuration options for validation, formatting, parsing, and behavior customization.

interface UseFieldConfig extends UseFieldAutoConfig {
  /** Field state subscription configuration */
  subscription?: FieldSubscription;
}

interface UseFieldAutoConfig {
  /** Callback after successful submission */
  afterSubmit?: () => void;
  /** Allow null values instead of undefined */
  allowNull?: boolean;
  /** Callback before submission, return false to prevent */
  beforeSubmit?: () => void | false;
  /** Component to render (alternative to render prop) */
  component?: React.ComponentType<any> | SupportedInputs;
  /** Custom data attached to field */
  data?: Record<string, any>;
  /** Default value when field is undefined */
  defaultValue?: any;
  /** Function to format value for display */
  format?: (value: any, name: string) => any;
  /** Whether to format on blur instead of every change */
  formatOnBlur?: boolean;
  /** Initial field value */
  initialValue?: any;
  /** Custom equality function for value comparison */
  isEqual?: (a: any, b: any) => boolean;
  /** Multiple selection support */
  multiple?: boolean;
  /** Function to parse display value to stored value */
  parse?: (value: any, name: string) => any;
  /** Input type attribute */
  type?: string;
  /** Field validation function */
  validate?: FieldValidator<any>;
  /** Other fields to validate when this field changes */
  validateFields?: string[];
  /** Controlled field value */
  value?: any;
}

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

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

type SupportedInputs = "input" | "select" | "textarea";

Usage Examples:

// Field with formatting and parsing
function CurrencyField() {
  const format = (value: number) => {
    if (value === undefined) return "";
    return new Intl.NumberFormat("en-US", {
      style: "currency",
      currency: "USD",
    }).format(value);
  };

  const parse = (value: string) => {
    const number = parseFloat(value.replace(/[^0-9.-]/g, ""));
    return isNaN(number) ? undefined : number;
  };

  return (
    <Field
      name="price"
      format={format}
      parse={parse}
    >
      {({ input, meta }) => (
        <div>
          <label>Price</label>
          <input {...input} type="text" placeholder="$0.00" />
          {meta.error && meta.touched && <span>{meta.error}</span>}
        </div>
      )}
    </Field>
  );
}

// Field with custom validation
function EmailField() {
  const validateEmail = (value: string) => {
    if (!value) return "Required";
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
      return "Invalid email address";
    }
    return undefined;
  };

  return (
    <Field
      name="email"
      validate={validateEmail}
      subscription={{ value: true, error: true, touched: true }}
    >
      {({ input, meta }) => (
        <div>
          <label>Email</label>
          <input {...input} type="email" />
          {meta.error && meta.touched && <span>{meta.error}</span>}
        </div>
      )}
    </Field>
  );
}

// Field with component prop
function ComponentField() {
  const TextInput = ({ input, meta, ...props }: any) => (
    <div>
      <input {...input} {...props} />
      {meta.error && meta.touched && <span>{meta.error}</span>}
    </div>
  );

  return (
    <Field
      name="description"
      component={TextInput}
      type="text"
      placeholder="Enter description"
    />
  );
}

Field State Management

Fields maintain comprehensive state information and support advanced state management features.

interface FieldState<FieldValue = any> {
  /** Whether field is currently active (focused) */
  active?: boolean;
  /** Custom data attached to field */
  data?: Record<string, any>;
  /** Whether field value differs from initial */
  dirty?: boolean;
  /** Whether field is dirty since last submit */
  dirtySinceLastSubmit?: boolean;
  /** Current validation error */
  error?: any;
  /** Initial field value */
  initial?: FieldValue;
  /** Whether field has validation errors */
  invalid?: boolean;
  /** Array length for array fields */
  length?: number;
  /** Whether field was ever modified */
  modified?: boolean;
  /** Whether field was modified since last submit */
  modifiedSinceLastSubmit?: boolean;
  /** Whether field value equals initial value */
  pristine?: boolean;
  /** Submission error for this field */
  submitError?: any;
  /** Whether last submission failed */
  submitFailed?: boolean;
  /** Whether last submission succeeded */
  submitSucceeded?: boolean;
  /** Whether form is currently submitting */
  submitting?: boolean;
  /** Whether field was ever focused */
  touched?: boolean;
  /** Whether field passes validation */
  valid?: boolean;
  /** Whether field is currently being validated */
  validating?: boolean;
  /** Current field value */
  value?: FieldValue;
  /** Whether field was ever visited (focused then blurred) */
  visited?: boolean;
}

Array Fields

Fields support array operations for dynamic field lists and complex data structures.

/**
 * Array field operations available through field meta when length > 0
 */
interface ArrayFieldMeta extends FieldMeta {
  /** Number of items in the array */
  length?: number;
}

Usage Example:

function ArrayField() {
  return (
    <Field name="items">
      {({ input, meta }) => (
        <div>
          <label>Items ({meta.length || 0})</label>
          {/* Array field rendering logic */}
          {meta.length && <div>Array has {meta.length} items</div>}
        </div>
      )}
    </Field>
  );
}

Install with Tessl CLI

npx tessl i tessl/npm-react-final-form

docs

field.md

form-spy.md

form.md

hooks.md

index.md

typescript.md

tile.json