Reactive flow
A diagram of the form’s reactive flow — how options, internal state, and public API connect:
flowchart TD
subgraph Options["Options (createForm)"]
schema["schema"]
uiSchema["uiSchema"]
uiOptionsRegistry["uiOptionsRegistry"]
initialValue["initialValue"]
value["value (Bind)"]
initialErrors["initialErrors"]
disabled["disabled"]
fieldsValidationMode["fieldsValidationMode"]
end
subgraph Internal["Internal"]
validator["validator"]
merger["merger"]
end
subgraph InternalState["Internal State"]
pathsTrieRef["pathsTrieRef"]
fieldsStateMap["fieldsStateMap"]
errors["errors (FormErrors)"]
end
subgraph FormState["FormState"]
formValue["value"]
formIsSubmitted["isSubmitted"]
formIsChanged["isChanged"]
submission["submission"]
fieldsValidation["fieldsValidation"]
end
subgraph Queries["Queries"]
getValueSnapshot["getValueSnapshot"]
getFieldErrors["getFieldErrors"]
hasErrors["hasErrors"]
getErrors["getErrors"]
validate["validate"]
getComponent["getComponent"]
getFieldComponent["getFieldComponent"]
retrieveSchema["retrieveSchema"]
isDisabled["isDisabled"]
hasFieldStateByPath["hasFieldStateByPath"]
end
subgraph Commands["Commands"]
updateErrors["updateErrors"]
updateFieldErrors["updateFieldErrors"]
setValue["setValue"]
validateField["validateField"]
setFieldStateByPath["setFieldStateByPath"]
end
schema --> validator
uiSchema --> validator
uiOptionsRegistry --> validator
validator --> merger
schema --> merger
uiSchema --> merger
schema --> pathsTrieRef
merger --> formValue
schema --> formValue
value --> formValue
initialValue --> formValue
pathsTrieRef --> formIsSubmitted
pathsTrieRef --> formIsChanged
fieldsStateMap --> formIsSubmitted
fieldsStateMap --> formIsChanged
validator --> submission
validator --> fieldsValidation
initialErrors --> errors
formValue -.-> getValueSnapshot
errors -.-> getFieldErrors
errors -.-> hasErrors
errors -.-> getErrors
formValue -.-> validate
FormState -.-> getComponent
FormState -.-> getFieldComponent
FormState -.-> retrieveSchema
FormState -.-> isDisabled
fieldsStateMap -.-> hasFieldStateByPath
errors -.-> updateErrors
errors -.-> updateFieldErrors
formValue -.-> setValue
fieldsValidation -.-> validateField
fieldsStateMap -.-> setFieldStateByPath
Event Flows
Section titled “Event Flows”What happens when the user interacts with the form:
Field Input
Section titled “Field Input”flowchart TD
domInput["DOM input event"]
customHandler{"config.eventHandlers\n.oninput?"}
customRun["eventHandlers.oninput()"]
setFieldState["setFieldState(ctx, path, FIELD_INPUTTED)"]
mapSet["fieldsStateMap.set(path, flags | FIELD_INPUTTED)"]
isChanged["isChanged = true\n(map.size > 0)"]
validationCheck{"fieldsValidationMode\nincludes ON_INPUT?"}
afterCheck{"Modifier preconditions met?"}
afterSubmitted{"AFTER_SUBMITTED set?\nisSubmitted = true?"}
afterChanged{"AFTER_CHANGED set?\nFIELD_CHANGED set?"}
afterTouched{"AFTER_TOUCHED set?\nFIELD_BLURRED set?"}
skipValidation["skip validation"]
debounce["debounce wrapper\n(default 300ms)"]
runValidation["fieldsValidation.run(config, value)"]
combinator{"combinator check\n(default: abortPrevious)"}
abort["abort previous task"]
waitPrevious["wait for previous\nto complete"]
validate["validator.validateFieldValue\nor validateFieldValueAsync"]
onSuccess["onSuccess"]
updateErrors["updateFieldErrors(ctx, path, fieldErrors)"]
hasErrors{"fieldErrors\nempty?"}
clearFieldErrors["clear errors for path"]
setFieldErrors["set errors for path"]
onFailure["onFailure"]
setErrorMsg["updateFieldErrors(ctx, path,\n[translate('validation-process-error',\n{ error })])"]
onFieldsValidationFailure["options.onFieldsValidationFailure\n(error, config, value)"]
done["done"]
domInput --> customHandler
customHandler -->|yes| customRun
customHandler -->|no| setFieldState
customRun --> setFieldState
setFieldState --> mapSet
mapSet --> isChanged
setFieldState --> validationCheck
validationCheck -->|yes| afterCheck
validationCheck -->|no| done
afterCheck --> afterSubmitted
afterSubmitted -->|yes| afterChanged
afterSubmitted -->|no| skipValidation
afterChanged -->|yes| afterTouched
afterChanged -->|no| skipValidation
afterTouched -->|yes| debounce
afterTouched -->|no| skipValidation
skipValidation --> done
debounce --> runValidation
runValidation --> combinator
combinator -->|abort| abort
combinator -->|wait| waitPrevious
combinator -->|proceed| validate
abort --> validate
waitPrevious --> validate
validate --> onSuccess
validate --> onFailure
onSuccess --> updateErrors
updateErrors --> hasErrors
hasErrors -->|yes| setFieldErrors
hasErrors -->|no| clearFieldErrors
setFieldErrors --> done
clearFieldErrors --> done
onFailure --> setErrorMsg
setErrorMsg --> onFieldsValidationFailure
onFieldsValidationFailure --> done
Form Submit
Section titled “Form Submit”flowchart TD
domSubmit["DOM submit event"]
prevent["e.preventDefault()"]
run["submission.run(e)"]
combinator{"combinator check\n(default: waitPrevious)"}
ignore["ignore request\n(currently processing)"]
proceed["proceed"]
setState["setFieldState(formState, rootPath, FIELD_SUBMITTED)"]
isSubmitted["isSubmitted = true"]
snapshot["$state.snapshot(valueRef.current)"]
validate["validator.validateFormValue\nor validateFormValueAsync"]
taskState["Task state: processing"]
taskDelayed{"delayedMs\n(default 500ms)?"}
delayed["Task state: processing\n(delayed: true)"]
taskTimeout{"timeoutMs\n(default 8000ms)?"}
timeout["Task state: failed\n(reason: timeout)"]
validateResult{"validation result"}
valid{"result.errors\n=== undefined?"}
updateErrors["updateErrors(formState, [])"]
clearFields["fieldsStateMap.clear()"]
isChanged["isChanged = false"]
onSubmit["options.onSubmit(value, event)"]
taskSuccess["Task state: success"]
updateErrorsInvalid["updateErrors(formState, result.errors)"]
onSubmitError["options.onSubmitError(result, event, formState)"]
onFailure["onFailure"]
updateFieldErrors["updateFieldErrors(formState, rootPath,\n[translate('validation-process-error',\n{ error })])"]
onSubmissionFailure["options.onSubmissionFailure(error, event)"]
taskFailed["Task state: failed"]
domSubmit --> prevent
prevent --> run
run --> combinator
combinator -->|ignore| ignore
combinator -->|proceed| proceed
proceed --> setState
setState --> isSubmitted
proceed --> snapshot
snapshot --> validate
validate --> taskState
taskState --> taskDelayed
taskDelayed -->|yes| delayed
taskDelayed -->|no| taskTimeout
delayed --> taskTimeout
taskTimeout -->|yes| timeout
taskTimeout -->|no| validateResult
timeout --> onFailure
validateResult --> valid
valid -->|yes| updateErrors
valid -->|no| updateErrorsInvalid
updateErrors --> clearFields
clearFields --> isChanged
updateErrors --> onSubmit
onSubmit --> taskSuccess
updateErrorsInvalid --> onSubmitError
onSubmitError --> taskFailed
onFailure --> updateFieldErrors
updateFieldErrors --> onSubmissionFailure
onSubmissionFailure --> taskFailed
Form Reset
Section titled “Form Reset”flowchart TD
trigger["Reset trigger"]
isEvent{"event provided?"}
prevent["e.preventDefault()"]
clearState["fieldsStateMap.clear()"]
allFlags["All field state flags wiped"]
isChanged["isChanged = false\n(map.size === 0)"]
isSubmitted["isSubmitted = false\n(no SUBMITTED flag on root)"]
clearErrors["errors.clear()"]
allErrorsRemoved["All validation errors removed"]
mergeDefaults["merger.mergeFormDataAndSchemaDefaults"]
mergeArgs["{ formData: options.initialValue,\n schema: options.schema }"]
setValue["valueRef.current = merged value"]
valueReset["Form value restored to initial state"]
reconcile["createFormValueReconciler\n(reconciles keyed arrays)"]
onReset["options.onReset(e)"]
done["done"]
trigger --> isEvent
isEvent -->|yes| prevent
isEvent -->|no| clearState
prevent --> clearState
clearState --> allFlags
allFlags --> isChanged
allFlags --> isSubmitted
clearState --> clearErrors
clearErrors --> allErrorsRemoved
clearState --> mergeDefaults
mergeDefaults --> mergeArgs
mergeArgs --> setValue
setValue --> valueReset
valueReset --> reconcile
reconcile --> onReset
allErrorsRemoved --> onReset
isChanged --> onReset
onReset --> done