Skip to content

Analytics

Track form behavior without coupling metrics to rendering.

Analytics callbacks report start, field, page, completion, reset, and abandon events while your form stays a normal React component.

Configuration

Analytics is a callback object passed to useFormedible. Current events cover form start, field focus, field blur, field change, field complete, field error, page change, form complete, abandon, and reset.

  • Field callback names use Extract<keyof TFormValues, string> | string, so nested paths are allowed.
  • Runtime timestamps come from Date.now; blur time is the blur timestamp minus the stored focus timestamp.
  • Page completion, tab analytics, and performance callbacks are typed as never and are not emitted.
PropertyTypeDefaultDescription
onFormStart
(timestamp: number) => void
undefinedRuns once from the analytics hook mount effect.
onFieldFocus
(fieldName: Extract<keyof TFormValues, string> | string, timestamp: number) => void
undefinedRuns when a field receives focus.
onFieldBlur
(fieldName: Extract<keyof TFormValues, string> | string, timeSpent: number) => void
undefinedRuns on blur with elapsed focus time.
onFieldChange
(fieldName: Extract<keyof TFormValues, string> | string, value: unknown, timestamp: number) => void
undefinedRuns after a field change with the new field value.
onFieldComplete
(fieldName: Extract<keyof TFormValues, string> | string, isValid: boolean, timeSpent: number) => void
undefinedRuns after blur with the latest validity flag and elapsed focus time.
onFieldError
(fieldName: Extract<keyof TFormValues, string> | string, errors: readonly string[], timestamp: number) => void
undefinedRuns when blur receives field errors, or when the standalone tracker records errors.
onPageChange
(fromPage: number, toPage: number, timeSpent: number, pageValidationState?: { readonly hasErrors: boolean; readonly completionPercentage: number }) => void
undefinedRuns after page movement with timing and validation state for the page being left.
onFormComplete
(timeSpent: number, formData: TFormValues) => void
undefinedRuns after Formedible tracks a successful submit.
onFormAbandon
(completionPercentage: number, context?: { readonly currentPage?: number; readonly currentTab?: string; readonly lastActiveField?: string }) => void
undefinedRuns from cleanup if the form unmounts before completion.
onFormReset
(timestamp: number, reason?: string) => void
undefinedRuns when reset tracking is called. The built-in reset path passes the reset reason when supplied.

Field events

Field tracking is wired through the FieldRenderer controller from useFormedible. Focus stores time, change reports the next value, and blur reports elapsed focus time plus validity.

  • trackFieldFocus stores lastActiveField and focusedAt[fieldName], then calls onFieldFocus.
  • trackFieldChange calls onFieldChange with fieldName, value, and Date.now().
  • trackFieldBlur calls onFieldBlur, optional onFieldError, then onFieldComplete, and removes the stored focus timestamp.
  • getFieldBlurTime returns 0 when blur occurs without a stored focus timestamp.

Page and form events

Page changes start in useMultiPage. useFormedible passes the page context to analytics.trackPageChange and the public onPageChange option.

  • useMultiPage measures timeSpent as Date.now() minus pageStartedAt before it changes the page.
  • analytics.trackPageChange includes hasErrors and completionPercentage for the page being left.
  • trackFormComplete sets completedRef before onFormComplete, so abandon does not fire after a completed submit.
  • The built-in reset path passes reason "reset" to trackFormReset.

Abandonment tracking

Abandonment runs in the analytics hook cleanup. It is skipped after trackFormComplete, so unmounting an incomplete form calls onFormAbandon when you provide it.

  • useFormedible calculates completionPercentage from completed fields divided by total fields.
  • currentPage is always included; currentTab is included when tab state is active.
  • lastActiveField comes from getAbandonContext or the focus tracker fallback.
  • When no getAbandonContext is supplied, the analytics hook falls back to completionPercentage: 0.

Standalone factory

createFormAnalyticsTracker is exported from use-form-analytics.ts for code outside React. It takes the same analytics config plus an optional clock.

  • options.now defaults to Date.now.
  • trackFieldChange and trackFieldError include a current timestamp from the configured clock.
  • trackFieldComplete forwards isValid and timeSpent without React focus state.
  • trackFormReset forwards an optional reason string.
PropertyTypeDefaultDescription
trackFieldChange
(fieldName: Extract<keyof TFormValues, string> | string, value: unknown) => void
ReturnedCalls onFieldChange with the current clock value.
trackFieldComplete
(fieldName: Extract<keyof TFormValues, string> | string, isValid: boolean, timeSpent: number) => void
ReturnedCalls onFieldComplete without React focus state.
trackFieldError
(fieldName: Extract<keyof TFormValues, string> | string, errors: readonly string[]) => void
ReturnedCalls onFieldError with the current clock value.
trackFormReset
(reason?: string) => void
ReturnedCalls onFormReset with the current clock value and optional reason.

Formedible

TanStack Form, shadcn/ui, Zod