Validation, schema, expression, and author-defined

Three layers of field validation, when each runs, and how errors surface in the UI.

Validation in SharePoint Forms365 runs at three layers, in order:

1. Schema validation (declarative)

Built into every field type. No code:

PropertyDescription
required
boolean
Field must have a value.
requiredIf
expression
Required only when the expression returns true. See the requiredIf reference.
minLength / maxLength
number
Text-length bounds.
min / max
number | date
Numeric / date bounds.
pattern
regex
Text must match the regular expression.

2. Expression validation

The field's Custom validation rule (assertExpression) runs an

expression at save time. The field is valid only while that expression is true, and Custom validation message ( assertMessage) is what the user sees when it is not. Inside this rule, and only here, $value means the field's own value:

On the End date field: never before Start

$value >= {StartDate}

On a consent checkbox: must be ticked

$value == true

3. Author validation (JavaScript)

The most expressive layer. Per-field onValidate handlers receive the current value and return either nothing (valid) or a string (invalid, the string becomes the error message):

Custom email-domain validation

f365.field('ContactEmail').on('validate', (value) => {
  const domain = (value ?? '').split('@')[1]?.toLowerCase();
  if (!domain?.endsWith('.gov.au')) return 'Must be a .gov.au email address.';
});

Async validation against an external API

f365.field('Sku').on('validate', async (value) => {
  if (!value) return;
  const exists = await f365.http.get<{ active: boolean }>(`/api/sku/${value}`);
  if (!exists?.active) return 'SKU not found or inactive.';
});

Form-level onValidate runs after every field-level handler and gets the whole form payload, useful for cross-field rules.

When validation runs

PropertyDescription
On blurField-level validation runs when the user leaves the field. Provides immediate feedback without being annoying.
On change (debounced)Some types (e.g. patterns on number fields) re-validate after a 300ms debounce while typing.
On submitEvery layer runs in order. The first failure focuses the bad field.

How errors render

Errors surface via the Fluent v9 Field's validationState slot, never as custom red-text markup. This means screen readers correctly announce the error via aria-describedby, and the visual treatment is consistent across every field type.

Related articles