State
export type FormSubmission<Output> = Task< [event: SubmitEvent], ValidationResult<Output>, unknown>;
export type FieldsValidation = Task< [config: Config, value: FieldValue], Update<string[]>, unknown>;
export interface FormState<T>export interface FormState<T> { readonly submission: FormSubmission<T>; readonly fieldsValidation: FieldsValidation; readonly isChanged: boolean; readonly isSubmitted: boolean;
submit: (e: SubmitEvent) => void; reset: (e?: Event) => void;
// Internals
[FORM_VALUE]: FormValue; readonly [FORM_ID_PREFIX]: string; readonly [FORM_ROOT_PATH]: FieldPath; readonly [FORM_ID_FROM_PATH]: (path: FieldPath) => Id; readonly [FORM_PATHS_TRIE_REF]: PathTrieRef<FieldPath>; readonly [FORM_ERRORS]: FormErrorsMap; 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]: Validator; 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; readonly [FORM_FIELDS_STATE_MAP]: SvelteMap<FieldPath, FieldState>;}Methods
Section titled “Methods”SJSF provides a set of functions to work with the form state that can either read (queries) or modify (commands) it.
Queries:
getComponent, getFieldComponent, getFieldErrors, getFieldErrorsByPath,
getFieldsErrors, getFieldsErrorsByPath, hasErrors, getErrors,
hasFieldState, hasFieldStateByPath, createId, createPath,
createChildPath, createPseudoPath, createPseudoId, createIdByPath,
createPseudoIdByPath, isSelect, isMultiSelect, isFilesArray,
retrieveSchema, sanitizeDataForNewSchema, getClosestMatchingOption,
getDefaultFieldState, retrieveUiSchema, uiTitleOption, retrieveUiOption,
retrieveNestedUiOption, uiOptionProps, uiOptionNestedProps,
retrieveTranslate, getFieldTitle, getFieldAction,
getFieldsValidationMode, validate, validateAsync, getValueSnapshot
Commands:
updateErrors, updateFieldErrors, updateFieldErrorsByPath,
setFieldStateByPath, validateField, validateAdditionalPropertyKey,
validateFileList, setValue
query vs command
Section titled “query vs command”In addition to the semantic difference, there is also a behavioral one when used in a reactive context.
When a query is called, the reactive variables it accesses will be tracked.
When a command is called, the accessed variables will not be tracked.
FieldPath vs RPath
Section titled “FieldPath vs RPath”You may have noticed that some methods have alternate versions with the ByPath suffix.
Their signatures differ in the type of the path argument: FieldPath or RPath.
Since JavaScript lacks a primitive for tuples, the library uses uniquified paths.
When an RPath (a regular array) is passed, it is automatically converted into a FieldPath and cached in a prefix tree.
Each identical path returns the same reference, allowing FieldPath to serve as a stable identifier or key in Map/WeakMap.
Therefore, ByPath versions of methods are intended for situations where you don’t have access to a FieldPath or are working with dynamically generated paths.
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
KeyedArrayAPI
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.