Validation
By default, form data when submitted will be validated using HTML5 validation and the provided validator.
Live validation
Section titled “Live validation”You can easily implement live validation by utilizing Svelte 5 reactivity
<script lang="ts"> import { untrack } from "svelte"; import { createForm, BasicForm, hasFieldStateByPath, type Schema, FIELD_INTERACTED, updateErrors, validate, } from "@sjsf/form";
import * as defaults from "@/lib/form/defaults";
const schema: Schema = { title: "Live validation", properties: { foo: { type: "string", minLength: 10, }, bar: { type: "number", minimum: 1000, }, }, };
const form = createForm({ ...defaults, initialValue: { foo: "initial", bar: 1, }, schema, onSubmit: console.log, });
$effect(() => { // NOTE: `validate()` reads the state snapshot, // causing `$effect` to subscribe to all changes. const { errors = [] } = validate(form); updateErrors( form, untrack(() => errors.filter((e) => hasFieldStateByPath(form, e.path, FIELD_INTERACTED) ) ) ); });</script>
<BasicForm {form} />While it is possible, this approach has low efficiency because it is usually not meaningful to validate the entire form when only one field is changed.
Fields validation
Section titled “Fields validation”Instead of performing a full form validation every time a field is changed, we propose to validate only the field being changed and full validation of the form on submission.
<script lang="ts"> import { ON_CHANGE, ON_INPUT, SimpleForm } from "@sjsf/form";
import * as defaults from "@/lib/form/defaults";
import { objectSchema, objectUiSchema } from "./demo-schemas";</script>
<SimpleForm {...defaults} schema={objectSchema} uiSchema={objectUiSchema} fieldsValidationMode={ON_INPUT | ON_CHANGE}/>
The form in the example above, will validate fields on input and change events.
Async validation
Section titled “Async validation”The form supports asynchronous validation. By default:
- a new form validation process can only be started after the previous one is completed;
- a new fields validation process aborts the previous one;
- fields validation abort errors are not displayed.
Async form
<script lang="ts"> import Ajv, { type AsyncSchema, type SchemaValidateFunction } from "ajv"; import { addFormComponents, createAsyncFormValidator, } from "@sjsf/ajv8-validator"; import { ON_INPUT, BasicForm, createForm, hasErrors } from "@sjsf/form";
import * as defaults from "@/lib/form/defaults";
const ajv = addFormComponents(new Ajv()); const validate: SchemaValidateFunction = async (schema, data) => { await new Promise((resolve) => setTimeout(resolve, 600)); if (Math.random() > 0.7) { throw new Error("async error"); } return data.length >= schema.minimum && data.length <= schema.maximum; }; ajv.addKeyword({ keyword: "asyncLength", async: true, type: "string", validate, });
const schema: AsyncSchema = { $async: true, type: "string", pattern: "^\\d+$", asyncLength: { minimum: 3, maximum: 6, }, };
const form = createForm({ ...defaults, validator: (options) => createAsyncFormValidator({ ...options, ajv }), schema, fieldsValidationMode: ON_INPUT, onSubmit: console.log, });</script>
<p> The form accepts a sequence of digits (checked synchronously) with the number of digits from 3 to 6 (checked asynchronously, with a 70% chance of successful verification)</p><p> form validation: {form.submission.status}, fields validation: {form .fieldsValidation.status}, errors: {hasErrors(form)}</p><BasicForm {form} novalidate autocomplete="off" />Please see your validator page for more information.
Focus on first error
Section titled “Focus on first error”You can achieve focus on the first error by using the createFocusOnFirstError function.
<script lang="ts"> import { SimpleForm } from "@sjsf/form"; import { createFocusOnFirstError } from "@sjsf/form/focus-on-first-error";
import * as defaults from "@/lib/form/defaults";
import { objectSchema, objectUiSchema } from "./demo-schemas";</script>
<SimpleForm {...defaults} schema={objectSchema} uiSchema={objectUiSchema} onSubmitError={createFocusOnFirstError()}/>
focusOnFirstErrorwill try to find a focusable element and focus it.- If it’s not found, it will try to find an errors list and scroll it into view.
- If it’s not found, it will return
false, so you can extend the behavior.
Errors list
Section titled “Errors list”If necessary, you can create a list of errors
<script lang="ts"> import { BasicForm, createForm, getErrors, hasErrors } from "@sjsf/form";
import * as defaults from "@/lib/form/defaults";
import { objectSchema } from "./demo-schemas";
const form = createForm({ ...defaults, schema: objectSchema, });</script>
<BasicForm {form} novalidate />
{#if hasErrors(form)} <div style="padding-top: 1rem;"> <span style="font-size: larger; font-weight: bold;">Errors</span> <ui style="color: red;"> {#each getErrors(form) as [path, errors] (path)} {#each errors as error} <li>{error}</li> {/each} {/each} </ui> </div>{/if}
State transformation
Section titled “State transformation”In some cases it may be necessary to transform the form state before it is passed to the validator.
You can do this by extending the validator.
Omit extra data
Section titled “Omit extra data”One of the transformation options you can apply is deleting unnecessary data.
For this you can use omitExtraData function.
import { createForm, type FormValueValidator } from "@sjsf/form";import { omitExtraData } from "@sjsf/form/omit-extra-data";
import * as defaults from '@/lib/form/defaults'
import { schema, type FormValue } from "./schema";
const form = createForm<FormValue>({ ...defaults, validator: (options) => { const v = defaults.validator<FormValue>(options) return { ...v, validateFormValue(rootSchema, formValue) { const cleanData = omitExtraData( v, options.merger(), options.schema, formValue ); return v.validateFormValue(rootSchema, cleanData); }, } satisfies FormValueValidator<FormValue>; }, schema, onSubmit(value) { console.log("transformed", value); }, onSubmitError({ value, errors }) { console.log("transformed", value); console.log("errors", errors); }})
// Obtaining a value with the applied transformationconst { value } = validate(form)You can also use the withOmitExtraData(defaults.validator) function from the
@sjsf/form/validators/omit-extra-data module to achieve the same effect.