Validation
By default, form data when submitted will be validated using HTML5 validation and the provided validator.
Live validation (not recommended)
You can easily implement live validation by utilizing Svelte 5 reactivity
<script lang="ts"> import { createForm3, RawForm, type Schema } from "@sjsf/form"; import { translation } from "@sjsf/form/translations/en"; import { theme } from "@sjsf/form/basic-theme"; import { createValidator2 } from "@sjsf/ajv8-validator";
const validator = createValidator2();
const schema: Schema = { type: "string", minLength: 10, };
const form = createForm3({ ...theme, initialValue: "initial", schema, validator, translation, onSubmit: console.log, });
$effect(() => { form.errors = form.validate(); });</script>
<RawForm {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
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, ON_BLUR } from "@sjsf/form";
import CustomForm from "@/components/custom-form.svelte";
import { objectSchema, objectUiSchema } from "./_demo-schemas";</script>
<CustomForm schema={objectSchema} uiSchema={objectUiSchema} fieldsValidationMode={ON_INPUT | ON_CHANGE | ON_BLUR}/>
The form in the example above, will validate fields on input
, blur
and change
events.
Async validation
The form supports asynchronous validation.
To correctly display potential validation process errors, the handleValidationProcessError
option should be used.
<script lang="ts"> import Ajv, { type AsyncSchema, type SchemaValidateFunction } from "ajv"; import { addFormComponents, createAsyncValidator, } from "@sjsf/ajv8-validator"; import { ON_INPUT, RawForm } from "@sjsf/form"; import { handleValidationProcessError } from "@sjsf/form/translations/en"; import { Status } from "@sjsf/form/use-mutation.svelte";
import { createCustomForm } from "@/components/custom-form";
const ajv = addFormComponents(new Ajv()); const validate: SchemaValidateFunction = async (schema, data) => { await new Promise((resolve) => setTimeout(resolve, 1000)); if (Math.random() > 0.5) { 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: 7, }, };
const form = createCustomForm({ validator: createAsyncValidator({ ajv }), handleValidationProcessError, schema: schema, fieldsValidationMode: ON_INPUT, onSubmit: console.log, });
const statusNames: Record<Status, string> = { [Status.IDLE]: "idle", [Status.Processed]: "processed", [Status.Success]: "success", [Status.Failed]: "failed", };</script>
form validation: {statusNames[form.validation.status]}, fields validation: {statusNames[ form.fieldsValidation.status]}<RawForm {form} novalidate />
Please see your validator page for more information.
Focus on first error
You can achieve focus on the first error by using the focusOnFirstError
function.
<script lang="ts"> import { focusOnFirstError } from "@sjsf/form/focus-on-first-error";
import CustomForm from '@/components/custom-form.svelte';
import { objectSchema, objectUiSchema } from "./_demo-schemas";</script>
<CustomForm schema={objectSchema} uiSchema={objectUiSchema} onSubmitError={focusOnFirstError}/>
focusOnFirstError
will 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
If necessary, you can create a list of errors
<script lang="ts"> import { RawForm } from "@sjsf/form";
import { createCustomForm } from "@/components/custom-form";
import { objectSchema } from "./_demo-schemas";
const form = createCustomForm({ schema: objectSchema, });</script>
<RawForm {form} novalidate />
{#if form.errors.size > 0} <div style="padding-top: 1rem;"> <span style="font-size: larger; font-weight: bold;">Errors</span> <ui style="color: red;"> {#each form.errors as [field, fieldErrors] (field)} {#each fieldErrors as err} <li>"{err.propertyTitle}" {err.message}</li> {/each} {/each} </ui> </div>{/if}