diff --git a/packages/form-integrations/docs/17-validation-examples.md b/packages/form-integrations/docs/17-validation-examples.md
index 200c328d6..3e554134c 100644
--- a/packages/form-integrations/docs/17-validation-examples.md
+++ b/packages/form-integrations/docs/17-validation-examples.md
@@ -695,3 +695,92 @@ export const FormValidationReset = () => html`
`;
```
+
+## Backend validation
+
+Backend validation is needed in some cases. For example, you have a sign up form, the username could be already taken. You can add an `AsyncValidator` to check the availability when the `username` field is changed but you may have a conflict when you submit the form (another user take the username in parallel).
+
+```js preview-story
+export const backendValidation = () => {
+ // Mock
+ function fakeFetch(ms = 0, withError = false) {
+ return new Promise(resolve => {
+ setTimeout(() => {
+ resolve(
+ new Response(
+ JSON.stringify({
+ message: withError ? 'Username is already taken' : '',
+ }),
+ { status: withError ? 400 : 200 },
+ ),
+ );
+ }, ms);
+ });
+ }
+
+ let backendValidationResolver;
+ let backendErrorMessage = 'Unknown Error';
+ let isBackendCallPending = false;
+
+ const submitHandler = ev => {
+ const lionForm = ev.target;
+ if (lionForm.hasFeedbackFor.includes('error')) {
+ const firstFormElWithError = lionForm.formElements.find(el =>
+ el.hasFeedbackFor.includes('error'),
+ );
+ firstFormElWithError.focus();
+ return;
+ }
+ isBackendCallPending = true;
+ lionForm.formElements.username.validate(); // => backendValidationResolver will be assigned
+ const formData = lionForm.serializedValue;
+ fakeFetch(2000, formData.simulateError.length).then(async response => {
+ if (response.status !== 200) {
+ backendErrorMessage = (await response.json())?.message;
+ backendValidationResolver(true);
+ }
+ backendValidationResolver(false);
+ isBackendCallPending = false;
+ });
+ };
+
+ class BackendValidator extends Validator {
+ static get validatorName() {
+ return 'backendValidator';
+ }
+ static get async() {
+ return true;
+ }
+ async execute() {
+ if (isBackendCallPending) {
+ return await new Promise(resolve => (backendValidationResolver = resolve));
+ }
+ return false;
+ }
+ static getMessage({ fieldName, modelValue, params: param }) {
+ return backendErrorMessage;
+ }
+ }
+ return html`
+
+
+
+
+ `;
+};
+```