diff --git a/docs/config.json b/docs/config.json index f32786af4..9485e6baf 100644 --- a/docs/config.json +++ b/docs/config.json @@ -58,7 +58,7 @@ "children": [ { "label": "Quick Start", - "to": "react/quick-start" + "to": "framework/react/quick-start" } ] }, @@ -67,19 +67,19 @@ "children": [ { "label": "useForm", - "to": "react/reference/useForm" + "to": "framework/react/reference/useForm" }, { "label": "useField", - "to": "react/reference/useField" + "to": "framework/react/reference/useField" }, { "label": "Field", - "to": "react/reference/Field" + "to": "framework/react/reference/Field" }, { "label": "FormApi", - "to": "react/reference/formApi" + "to": "framework/react/reference/formApi" } ] }, @@ -88,7 +88,7 @@ "children": [ { "label": "Simple", - "to": "react/examples/simple" + "to": "framework/react/examples/simple" } ] } diff --git a/docs/framework/react/reference/Field.md b/docs/framework/react/reference/Field.md index 8fde22b5c..e10e1c3e8 100644 --- a/docs/framework/react/reference/Field.md +++ b/docs/framework/react/reference/Field.md @@ -33,9 +33,13 @@ export function Field({ A functional React component that renders a form field. -- `children: (fieldApi: FieldApi) => any` +- ```tsx + children: (fieldApi: FieldApi) => any + ``` - A render function that takes a field API instance and returns a React element. -- `fieldOptions: FieldOptions` +- ```tsx + fieldOptions: FieldOptions + ``` - The field options. The `Field` component uses the `useField` hook internally to manage the field instance. @@ -50,5 +54,7 @@ export function createFieldComponent( A factory function that creates a connected field component for a specific form API instance. -- `formApi: FormApi` +- ```tsx + formApi: FormApi + ``` - The form API instance to connect the field component to. diff --git a/docs/framework/react/reference/formApi.md b/docs/framework/react/reference/formApi.md index a778758ea..635dc9a6e 100644 --- a/docs/framework/react/reference/formApi.md +++ b/docs/framework/react/reference/formApi.md @@ -7,13 +7,23 @@ title: Form API When using `@tanstack/react-form`, the [core form API](../../core//reference/formApi.md) is extended with additional methods for React-specific functionality: -- `Form: FormComponent` +- ```tsx + Form: FormComponent + ``` - A pre-bound and type-safe form component, specific to this forms instance. -- `Field: FieldComponent` +- ```tsx + Field: FieldComponent + ``` - A pre-bound and type-safe field component, specific to this forms instance. -- `useField: UseField` +- ```tsx + useField: UseField + ``` - A pre-bound and type-safe custom hook to use fields from this form instance. -- `useStore>>(selector?: (state: NoInfer>) => TSelected): TSelected` +- ```tsx + useStore>>(selector?: (state: NoInfer>) => TSelected): TSelected + ``` - A custom hook to use the form store. -- `Subscribe>>(props: {selector?: (state: NoInfer>) => TSelected; children: ((state: NoInfer) => React.ReactNode) | React.ReactNode}): any` +- ```tsx + Subscribe>>(props: {selector?: (state: NoInfer>) => TSelected; children: ((state: NoInfer) => React.ReactNode) | React.ReactNode}): any + ``` - A subscription component to provide the selected form state to children. diff --git a/docs/framework/react/reference/useField.md b/docs/framework/react/reference/useField.md index 418b1074a..c308266ed 100644 --- a/docs/framework/react/reference/useField.md +++ b/docs/framework/react/reference/useField.md @@ -28,13 +28,17 @@ export function useField( A hook for managing a field in a form. -- `opts: FieldOptions` +- ```tsx + opts: FieldOptions + ``` - An object with field options. #### Returns -- `FieldApi` - - `FieldApi` instance for the specified field. +- ```tsx + FieldApi + ``` + - The `FieldApi` instance for the specified field. ### `createUseField` diff --git a/docs/overview.md b/docs/overview.md index f9c0e9971..883b80d09 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -3,20 +3,117 @@ id: overview title: Overview --- +TanStack Form is the ultimate solution for handling forms in web applications, providing a powerful and flexible approach to form management. Designed with first-class TypeScript support, headless UI components, and a framework-agnostic design, it streamlines form handling and ensures a seamless experience across various front-end frameworks. + ## Motivation -TODO +Most web frameworks do not offer a comprehensive solution for form handling, leaving developers to create their own custom implementations or rely on less-capable libraries. This often results in a lack of consistency, poor performance, and increased development time. TanStack Form aims to address these challenges by providing an all-in-one solution for managing forms that is both powerful and easy to use. + +With TanStack Form, developers can tackle common form-related challenges such as: + +- Reactive data binding and state management +- Complex validation and error handling +- Accessibility and responsive design +- Internationalization and localization +- Cross-platform compatibility and custom styling + +By providing a complete solution for these challenges, TanStack Form empowers developers to build robust and user-friendly forms with ease. ## Enough talk, show me some code already! -In the example below, you can see React Form in its most basic and simple form being used to fetch the GitHub stats for the React Form GitHub project itself: +In the example below, you can see TanStack Form in action, showcasing its simplicity and effectiveness in handling form data: [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-form/tree/main/examples/react/simple) ```tsx -TODO +import React from 'react' +import ReactDOM from 'react-dom/client' +import { useForm, FieldApi } from '@tanstack/react-form' + +function FieldInfo({ field }: { field: FieldApi }) { + return ( + <> + {field.state.meta.touchedError ? ( + {field.state.meta.touchedError} + ) : null}{' '} + {field.state.meta.isValidating ? 'Validating...' : null} + + ) +} + +export default function App() { + const form = useForm({ + // Memoize your default values to prevent re-renders + defaultValues: React.useMemo( + () => ({ + firstName: '', + lastName: '', + }), + [], + ), + onSubmit: async (values) => { + // Do something with form data + console.log(values) + }, + }) + + return ( +
+

Simple Form Example

+ {/* A pre-bound form component */} + +
+ {/* A type-safe and pre-bound field component*/} + !value && 'A first name is required'} + validateAsyncOn="change" + validateAsyncDebounceMs={500} + validateAsync={async (value) => { + await new Promise((resolve) => setTimeout(resolve, 1000)) + return ( + value.includes('error') && 'No "error" allowed in first name' + ) + }} + children={(field) => ( + // Avoid hasty abstractions. Render props are great! + <> + + + + + )} + /> +
+
+ ( + <> + + + + + )} + /> +
+ [state.canSubmit, state.isSubmitting]} + children={([canSubmit, isSubmitting]) => ( + + )} + /> +
+
+ ) +} + +const rootElement = document.getElementById('root')! +ReactDOM.createRoot(rootElement).render() ``` ## You talked me into it, so what now? -- Learn React Form at your own pace with our amazingly thorough [Walkthrough Guide](../installation) and [API Reference](../reference/useForm) +- Learn React Form at your own pace with our thorough [Walkthrough Guide](../installation) and [API Reference](../reference/FormApi) diff --git a/docs/reference/fieldApi.md b/docs/reference/fieldApi.md index ad3c937a2..386369219 100644 --- a/docs/reference/fieldApi.md +++ b/docs/reference/fieldApi.md @@ -15,23 +15,41 @@ const fieldApi: FieldApi = new FieldApi(formOptions: Field Options An object type representing the options for a field in a form. -- `name` +- ```tsx + name + ``` - The field name. If `TFormData` is `unknown`, the type will be `string`. Otherwise, it will be `DeepKeys`. -- `defaultValue?: TData` +- ```tsx + defaultValue?: TData + ``` - An optional default value for the field. -- `form?: FormApi` +- ```tsx + form?: FormApi + ``` - An optional reference to the form API instance. -- `validate?: (value: TData, fieldApi: FieldApi) => ValidationError | Promise` +- ```tsx + validate?: (value: TData, fieldApi: FieldApi) => ValidationError | Promise + ``` - An optional validation function for the field. -- `validatePristine?: boolean` +- ```tsx + validatePristine?: boolean + ``` - An optional flag indicating whether to validate the field when it is pristine (untouched). -- `defaultMeta?: Partial` +- ```tsx + defaultMeta?: Partial + ``` - An optional object with default metadata for the field. -- `validateOn?: ValidationCause` +- ```tsx + validateOn?: ValidationCause + ``` - An optional string indicating when to perform field validation. -- `validateAsyncOn?: ValidationCause` +- ```tsx + validateAsyncOn?: ValidationCause + ``` - An optional string indicating when to perform async field validation. -- `validateAsyncDebounceMs?: number` +- ```tsx + validateAsyncDebounceMs?: number + ``` - If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds. ### `ValidationCause` @@ -44,13 +62,21 @@ A type representing the cause of a validation event. An object type representing the metadata of a field in a form. -- `isTouched: boolean` +- ```tsx + isTouched: boolean + ``` - A flag indicating whether the field has been touched. -- `touchedError?: ValidationError` +- ```tsx + touchedError?: ValidationError + ``` - An optional error related to the touched state of the field. -- `error?: ValidationError` +- ```tsx + error?: ValidationError + ``` - An optional error related to the field value. -- `isValidating: boolean` +- ```tsx + isValidating: boolean + ``` - A flag indicating whether the field is currently being validated. ### `FieldApiOptions` @@ -65,101 +91,171 @@ A class representing the API for managing a form field. #### Properties -- `uid: number` +- ```tsx + uid: number + ``` - A unique identifier for the field instance. -- `form: FormApi` +- ```tsx + form: FormApi + ``` - A reference to the form API instance. -- `name: DeepKeys` +- ```tsx + name: DeepKeys + ``` - The field name. -- `store: Store>` +- ```tsx + store: Store> + ``` - The field state store. -- `state: FieldState` +- ```tsx + state: FieldState + ``` - The current field state. -- `options: RequiredByKey, 'validateOn'>` +- ```tsx + options: RequiredByKey, 'validateOn'> + ``` - The field options with the `validateOn` property set as required. #### Methods -- `constructor(opts: FieldApiOptions)` +- ```tsx + constructor(opts: FieldApiOptions) + ``` - Initializes a new `FieldApi` instance. -- `mount(): () => void` +- ```tsx + mount(): () => void + ``` - Mounts the field instance to the form. -- `updateStore(): void` +- ```tsx + updateStore(): void + ``` - Updates the field store with the latest form state. -- `update(opts: FieldApiOptions): void` +- ```tsx + update(opts: FieldApiOptions): void + ``` - Updates the field instance with new options. -- `getValue(): TData` +- ```tsx + getValue(): TData + ``` - Gets the current field value. -- `setValue(updater: Updater, options?: { touch?: boolean; notify?: boolean }): void` +- ```tsx + setValue(updater: Updater, options?: { touch?: boolean; notify?: boolean }): void + ``` - Sets the field value. -- `getMeta(): FieldMeta` +- ```tsx + getMeta(): FieldMeta + ``` - Gets the current field metadata. -- `setMeta(updater: Updater): void` +- ```tsx + setMeta(updater: Updater): void + ``` - Sets the field metadata. -- `getInfo(): any` +- ```tsx + getInfo(): any + ``` - Gets the field information object. -- `pushValue(value: TData): void` +- ```tsx + pushValue(value: TData): void + ``` - Pushes a new value to the field. -- `insertValue(index: number, value: TData): void` +- ```tsx + insertValue(index: number, value: TData): void + ``` - Inserts a value at the specified index. -- `removeValue(index: number): void` +- ```tsx + removeValue(index: number): void + ``` - Removes a value at the specified index. -- `swapValues(aIndex: number, bIndex: number): void` +- ```tsx + swapValues(aIndex: number, bIndex: number): void + ``` - Swaps the values at the specified indices. -- `getSubField>(name: TName): FieldApi, TFormData>` +- ```tsx + getSubField>(name: TName): FieldApi, TFormData> + ``` - Gets a subfield instance. -- `validate(): Promise` +- ```tsx + validate(): Promise + ``` - Validates the field value. -- `getChangeProps>(props: T = {} as T): ChangeProps & Omit>` +- ```tsx + getChangeProps>(props: T = {} as T): ChangeProps & Omit> + ``` - Gets the change and blur event handlers. -- `getInputProps(props: T = {} as T): InputProps & Omit` +- ```tsx + getInputProps(props: T = {} as T): InputProps & Omit + ``` - Gets the input event handlers. ### `FieldState` An object type representing the state of a field. -- `value: TData` +- ```tsx + value: TData + ``` - The current value of the field. -- `meta: FieldMeta` +- ```tsx + meta: FieldMeta + ``` - The current metadata of the field. ### `UserChangeProps` An object type representing the change and blur event handlers for a field. -- `onChange?: (updater: Updater) => void` +- ```tsx + onChange?: (updater: Updater) => void + ``` - An optional function to further handle the change event. -- `onBlur?: (event: any) => void` +- ```tsx + onBlur?: (event: any) => void + ``` - An optional function to further handle the blur event. ### `UserInputProps` An object type representing the input event handlers for a field. -- `onChange?: (event: any) => void` +- ```tsx + onChange?: (event: any) => void + ``` - An optional function to further handle the change event. -- `onBlur?: (event: any) => void` +- ```tsx + onBlur?: (event: any) => void + ``` - An optional function to further handle the blur event. ### `ChangeProps` An object type representing the change and blur event handlers for a field. -- `value: TData` +- ```tsx + value: TData + ``` - The current value of the field. -- `onChange: (updater: Updater) => void` +- ```tsx + onChange: (updater: Updater) => void + ``` - A function to handle the change event. -- `onBlur: (event: any) => void` +- ```tsx + onBlur: (event: any) => void + ``` - A function to handle the blur event. ### `InputProps` An object type representing the input event handlers for a field. -- `value: string` +- ```tsx + value: string + ``` - The current value of the field, coerced to a string. -- `onChange: (event: any) => void` +- ```tsx + onChange: (event: any) => void + ``` - A function to handle the change event. -- `onBlur: (event: any) => void` +- ```tsx + onBlur: (event: any) => void + ``` - A function to handle the blur event. diff --git a/docs/reference/formApi.md b/docs/reference/formApi.md index 85f7a13eb..5cd3f0956 100644 --- a/docs/reference/formApi.md +++ b/docs/reference/formApi.md @@ -15,25 +15,45 @@ const formApi: FormApi = new FormApi(formOptions: FormOptions) An object representing the options for a form. -- `defaultValues?: TData` +- ```tsx + defaultValues?: TData + ``` - The default values for the form fields. -- `defaultState?: Partial>` +- ```tsx + defaultState?: Partial> + ``` - The default state for the form. -- `onSubmit?: (values: TData, formApi: FormApi) => Promise` +- ```tsx + onSubmit?: (values: TData, formApi: FormApi) => Promise + ``` - A function to be called when the form is submitted and valid. -- `onInvalidSubmit?: (values: TData, formApi: FormApi) => void` +- ```tsx + onInvalidSubmit?: (values: TData, formApi: FormApi) => void + ``` - A function to be called when the form is submitted but invalid. -- `validate?: (values: TData, formApi: FormApi) => Promise` +- ```tsx + validate?: (values: TData, formApi: FormApi) => Promise + ``` - A function for custom validation logic for the form. -- `debugForm?: boolean` +- ```tsx + debugForm?: boolean + ``` - A boolean flag to enable or disable form debugging. -- `defaultValidatePristine?: boolean` +- ```tsx + defaultValidatePristine?: boolean + ``` - A boolean flag to enable or disable validation for pristine fields. -- `defaultValidateOn?: ValidationCause` +- ```tsx + defaultValidateOn?: ValidationCause + ``` - The default minimum cause for a field to be synchronously validated -- `defaultValidateAsyncOn?: ValidationCause` +- ```tsx + defaultValidateAsyncOn?: ValidationCause + ``` - The default minimum cause for a field to be asynchronously validated -- `defaultValidateAsyncDebounceMs?: number` +- ```tsx + defaultValidateAsyncDebounceMs?: number + ``` - The default time in milliseconds that if set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds. ### `FormApi` @@ -42,113 +62,203 @@ A class representing the Form API. It handles the logic and interactions with th #### Properties -- `options: FormOptions` +- ```tsx + options: FormOptions + ``` - The options for the form. -- `store: Store>` +- ```tsx + store: Store> + ``` - The internal store for the form state. -- `state: FormState` +- ```tsx + state: FormState + ``` - The current state of the form. -- `fieldInfo: Record, FieldInfo>` +- ```tsx + fieldInfo: Record, FieldInfo> + ``` - A record of field information for each field in the form. -- `fieldName?: string` +- ```tsx + fieldName?: string + ``` - An optional string representing the name of the field. -- `validationMeta: ValidationMeta` +- ```tsx + validationMeta: ValidationMeta + ``` - The validation metadata for the form. #### Methods -- `constructor(opts?: FormOptions)` +- ```tsx + constructor(opts?: FormOptions) + ``` - Constructs a new `FormApi` instance with the given form options. -- `update(options: FormOptions)` +- ```tsx + update(options: FormOptions) + ``` - Updates the form options and form state. -- `reset()` +- ```tsx + reset() + ``` - Resets the form state to the default values. -- `validateAllFields()` +- ```tsx + validateAllFields() + ``` - Validates all fields in the form. -- `validateForm()` +- ```tsx + validateForm() + ``` - Validates the form itself. -- `handleSubmit(e: FormEvent & { __handled?: boolean })` +- ```tsx + handleSubmit(e: FormEvent & { __handled?: boolean }) + ``` - Handles the form submission event, performs validation, and calls the appropriate onSubmit or onInvalidSubmit callbacks. -- `getFieldValue>(field: TField)` +- ```tsx + getFieldValue>(field: TField) + ``` - Gets the value of the specified field. -- `getFieldMeta>(field: TField)` +- ```tsx + getFieldMeta>(field: TField) + ``` - Gets the metadata of the specified field. -- `getFieldInfo>(field: TField)` +- ```tsx + getFieldInfo>(field: TField) + ``` - Gets the field info of the specified field. -- `setFieldMeta>(field: TField, updater: Updater) +- ```tsx + setFieldMeta>(field: TField, updater: Updater) + ``` - Updates the metadata of the specified field. -- `setFieldValue>(field: TField, updater: Updater>, opts?: { touch?: boolean }) +- ```tsx + setFieldValue>(field: TField, updater: Updater>, opts?: { touch?: boolean }) + ``` - Sets the value of the specified field and optionally updates the touched state. -- `pushFieldValue>(field: TField, value: DeepValue, opts?: { touch?: boolean }) +- ```tsx + pushFieldValue>(field: TField, value: DeepValue, opts?: { touch?: boolean }) + ``` - Pushes a value into an array field. -- `insertFieldValue>(field: TField, index: number, value: DeepValue, opts?: { touch?: boolean }) +- ```tsx + insertFieldValue>(field: TField, index: number, value: DeepValue, opts?: { touch?: boolean }) + ``` - Inserts a value into an array field at the specified index. -- `spliceFieldValue>(field: TField, index: number, opts?: { touch?: boolean }) +- ```tsx + spliceFieldValue>(field: TField, index: number, opts?: { touch?: boolean }) + ``` - Removes a value from an array field at the specified index. -- `swapFieldValues>(field: TField, index1: number, index2: number) +- ```tsx + swapFieldValues>(field: TField, index1: number, index2: number) + ``` - Swaps the values at the specified indices within an array field. ### `FormState` An object representing the current state of the form. -- `values: TData` +- ```tsx + values: TData + ``` - The current values of the form fields. -- `isFormValidating: boolean` +- ```tsx + isFormValidating: boolean + ``` - A boolean indicating if the form is currently validating. -- `formValidationCount: number` +- ```tsx + formValidationCount: number + ``` - A counter for tracking the number of validations performed on the form. -- `isFormValid: boolean` +- ```tsx + isFormValid: boolean + ``` - A boolean indicating if the form is valid. -- `formError?: ValidationError` +- ```tsx + formError?: ValidationError + ``` - A possible validation error for the form. -- `fieldMeta: Record, FieldMeta>` +- ```tsx + fieldMeta: Record, FieldMeta> + ``` - A record of field metadata for each field in the form. -- `isFieldsValidating: boolean` +- ```tsx + isFieldsValidating: boolean + ``` - A boolean indicating if any of the form fields are currently validating. -- `isFieldsValid: boolean` +- ```tsx + isFieldsValid: boolean + ``` - A boolean indicating if all the form fields are valid. -- `isSubmitting: boolean` +- ```tsx + isSubmitting: boolean + ``` - A boolean indicating if the form is currently submitting. -- `isTouched: boolean` +- ```tsx + isTouched: boolean + ``` - A boolean indicating if any of the form fields have been touched. -- `isSubmitted: boolean` +- ```tsx + isSubmitted: boolean + ``` - A boolean indicating if the form has been submitted. -- `isValidating: boolean` +- ```tsx + isValidating: boolean + ``` - A boolean indicating if the form or any of its fields are currently validating. -- `isValid: boolean` +- ```tsx + isValid: boolean + ``` - A boolean indicating if the form and all its fields are valid. -- `canSubmit: boolean` +- ```tsx + canSubmit: boolean + ``` - A boolean indicating if the form can be submitted based on its current state. -- `submissionAttempts: number` +- ```tsx + submissionAttempts: number + ``` - A counter for tracking the number of submission attempts. ### `FieldInfo` An object representing the field information for a specific field within the form. -- `instances: Record>` +- ```tsx + instances: Record> + ``` - A record of field instances with unique identifiers as keys. -- `validationCount?: number` +- ```tsx + validationCount?: number + ``` - A counter for tracking the number of validations performed on the field. -- `validationPromise?: Promise` +- ```tsx + validationPromise?: Promise + ``` - A promise representing the current validation state of the field. -- `validationResolve?: (error: ValidationError) => void` +- ```tsx + validationResolve?: (error: ValidationError) => void + ``` - A function to resolve the validation promise with a possible validation error. -- `validationReject?: (error: unknown) => void` +- ```tsx + validationReject?: (error: unknown) => void + ``` - A function to reject the validation promise with an error. ### `ValidationMeta` An object representing the validation metadata for a field. -- `validationCount?: number` +- ```tsx + validationCount?: number + ``` - A counter for tracking the number of validations performed on the field. -- `validationPromise?: Promise` +- ```tsx + validationPromise?: Promise + ``` - A promise representing the current validation state of the field. -- `validationResolve?: (error: ValidationError) => void` +- ```tsx + validationResolve?: (error: ValidationError) => void + ``` - A function to resolve the validation promise with a possible validation error. -- `validationReject?: (error: unknown) => void` +- ```tsx + validationReject?: (error: unknown) => void + ``` - A function to reject the validation promise with an error. ### `ValidationError`