Skip to content
Playground

Validation

By default, form data when submitted will be validated using HTML5 validation and the provided validator.

You can easily implement live validation by utilizing Svelte 5 reactivity

<script lang="ts">
import { useForm2, SimpleForm, type Schema } from "@sjsf/form";
import { translation } from "@sjsf/form/translations/en";
import { theme } from "@sjsf/form/basic-theme";
import { createValidator } from "@sjsf/ajv8-validator";
const validator = createValidator();
const schema: Schema = {
type: "string",
minLength: 10,
};
const form = useForm2({
...theme,
initialValue: "initial",
schema,
validator,
translation,
onSubmit: console.log,
});
$effect(() => {
form.errors = form.validate();
});
</script>
<SimpleForm {form} style="display: flex; flex-direction: column; gap: 1rem" />

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, AFTER_SUBMITTED, SimpleForm } from "@sjsf/form";
import { useCustomForm } from "@/components/custom-form";
import { objectSchema } from "./_demo-schemas";
const form = useCustomForm({
schema: objectSchema,
fieldsValidationMode: ON_INPUT | ON_CHANGE | AFTER_SUBMITTED,
onSubmit: console.log,
});
</script>
<SimpleForm
{form}
novalidate
style="display: flex; flex-direction: column; gap: 1rem"
/>

The form in this example will validate fields during the input and change events only after the first submission of the form.

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, SimpleForm } from "@sjsf/form";
import { handleValidationProcessError } from '@sjsf/form/translations/en';
import { Status } from '@sjsf/form/use-mutation.svelte';
import { useCustomForm } 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 = useCustomForm({
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]}
<SimpleForm
{form}
novalidate
style="display: flex; flex-direction: column; gap: 1rem"
/>

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 { SimpleForm } from "@sjsf/form";
import { focusOnFirstError } from "@sjsf/form/focus-on-first-error";
import { useCustomForm } from "@/components/custom-form";
import { objectSchema } from "./_demo-schemas";
const form = useCustomForm({
schema: objectSchema,
onSubmit: console.log,
onSubmitError: focusOnFirstError,
});
</script>
<SimpleForm
{form}
novalidate
style="display: flex; flex-direction: column; gap: 1rem"
/>

  1. focusOnFirstError will try to find a focusable element and focus it.
  2. If it’s not found, it will try to find an errors list and scroll it into view.
  3. 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 { SimpleForm } from "@sjsf/form";
import { useCustomForm } from "@/components/custom-form";
import { objectSchema } from "./_demo-schemas";
const form = useCustomForm({
schema: objectSchema,
onSubmit: console.log,
});
</script>
<SimpleForm
{form}
novalidate
style="display: flex; flex-direction: column; gap: 1rem"
/>
{#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}