High performance subscription-based form state management for React
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Individual field components with subscription-based state management, validation, formatting, and parsing capabilities.
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>
);
}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"
/>
);
}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;
}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