State
export interface FormValidationResult<E> { formValue: FormValue; formErrors: FieldErrorsMap<E>;}
export type FormSubmission<V> = Task< [event: SubmitEvent], FormValidationResult<AnyFormValueValidatorError<V>>, unknown>;
export type FieldsValidation<V> = Task< [config: Config, value: FieldValue], FieldError<AnyFieldValueValidatorError<V>>[], unknown>;
export interface FormState<T, V extends Validator> extends Readonly<Required<IdOptions>> { readonly submission: FormSubmission<V>; readonly fieldsValidation: FieldsValidation<V>; /** * An accessor that maintains form state consistency: * * - A snapshot of the form state is returned on access * - Default values from JSON Schema are taken into account during assignment */ value: T | undefined; isSubmitted: boolean; isChanged: boolean; errors: FieldErrorsMap<PossibleError<V>>; submit: (e: SubmitEvent) => void; reset: (e: Event) => void; /** * Performs the following actions: * - Takes a snapshot of the current state * - Calls the corresponding validator method * - Groups errors * * Actions it does not perform: * - Updates the form error list * * @throws {InvalidValidatorError} If the validator does not have the corresponding method */ validate: () => FieldErrorsMap<PossibleError<V>>; validateAsync: ( signal: AbortSignal ) => Promise<FieldErrorsMap<PossibleError<V>>>;
/** Internals */
[FORM_VALUE]: FormValue; readonly [FORM_ROOT_ID]: Id; readonly [FORM_MARK_SCHEMA_CHANGE]: () => void; readonly [FORM_KEYED_ARRAYS]: KeyedArraysMap; readonly [FORM_FIELDS_VALIDATION_MODE]: number; readonly [FORM_SCHEMA]: Schema; readonly [FORM_UI_SCHEMA_ROOT]: UiSchemaRoot; readonly [FORM_UI_SCHEMA]: UiSchema; readonly [FORM_UI_OPTIONS_REGISTRY]: UiOptionsRegistry; readonly [FORM_UI_EXTRA_OPTIONS]?: ExtraUiOptions; readonly [FORM_VALIDATOR]: V; readonly [FORM_MERGER]: FormMerger; readonly [FORM_ICONS]?: Icons; readonly [FORM_DISABLED]: boolean; readonly [FORM_DATA_URL_TO_BLOB]: DataURLToBlob; readonly [FORM_TRANSLATION]: Translation; readonly [FORM_TRANSLATE]: Translate; readonly [FORM_RESOLVER]: ResolveFieldType; readonly [FORM_THEME]: Theme;}
Direct modification of form state
Section titled “Direct modification of form state”If you are using a controlled form, you should consider the following aspects:
Initialization
Section titled “Initialization”It is recommended to initialize the state as follows:
let value = $state( merger.mergeFormDataAndSchemaDefaults(initialValue, schema));
Arrays
Section titled “Arrays”To modify arrays, use one of the following methods:
- Reassign
value.array = value.array.concat(123)
- Use
KeyedArray
API
import { createForm, type KeyedArraysMap } from "@sjsf/form";
const keyedArraysMap: KeyedArraysMap = new WeakMap()let value = $state({ array: [] })const form = createForm({ keyedArraysMap, value: [() => value, (v) => (value = v)], // ...otherOptions})
const api = keyedArraysMap.get(value.array)if (api) { api.push(123)}
Internals
Section titled “Internals”The @sjsf/form
package exports a number of utility functions (e.g. getComponent
)
that let you safely interact with the form’s internal state.
These helpers are the preferred way to read or manipulate internals,
since they are considered part of the supported API and follow semantic versioning.
For advanced cases, you may also access raw internals
by importing symbols from @sjsf/form/internals
and using them on a FormState
instance.
If you need functionality that isn’t covered by the exported helpers, please open an issue or start a discussion on GitHub. This way we can continue improving the API for everyone.