Skip to main content

Validator provider

Maps a validation rule the backend put in the schema to the validator that enforces it in the form.

Use it when the backend introduces a rule type the library does not know, or when a built-in rule needs a different check than the default one. Everything else about validation is automatic: rules declared on the backend field (Python) travel in options.validators and are applied to the generated input without any wiring here.

Signature​

type AdminValidatorProvider = (props: {
rule: ValidatorRule;
source: string;
resource?: string;
}) => Validator | undefined | null;

Parameters​

NameTypeDescription
ruleValidatorRuleThe rule to map — its type, value and optional message
sourcestringField the rule belongs to
resourcestringResource the field belongs to

ValidatorRule is documented with the field schema.

Returns​

A react-admin Validator to handle the rule, undefined to defer to defaultValidatorProvider, or null to suppress the rule so no validator runs for it.

caution

Unlike the field, input, button and box providers, this one exists only admin-wide — there is no validatorProvider prop on SchemaResource. Branch on resource inside the provider to make a rule behave differently for one resource.

Built-in mapping​

defaultValidatorProvider handles the five rule types of the contract:

rule.typeValidatorrule.value
max_lengthmaxLengthnumber
min_lengthminLengthnumber
max_valuemaxValuenumber
min_valueminValuenumber
regex—string — the pattern

rule.message becomes the error text; without it react-admin's generic translation is used, and for regex the translation of ra.validation.invalid_format ("Invalid format"). All five ignore an empty value — presence stays the job of the field's required flag, which the generated input applies on its own.

caution

A regex pattern that JavaScript cannot compile (a Python-only construct, for instance) is skipped with a console.warn and left to backend validation, so the form submits and the server rejects it. Keep patterns to syntax both languages share.

A value longer than 1000 characters is not matched against the pattern either. Matching backtracks super-linearly on a long input for patterns as ordinary as ^a*a*$, and the server enforces the rule regardless.

warning

The pattern the schema declares is what the browser runs, so an ambiguous one is the schema author's responsibility. ^(\w+\s?)*$ and its relatives — a repeated group whose body can itself repeat — take minutes to reject a value 30 characters long, on every keystroke that triggers validation, and there is no way for the frontend to interrupt a match already running. The flat equivalent, ^\w+( \w+)*$, matches the same values and stays fast because a space is mandatory between the repeats. Both the frontend and the backend run this pattern, so writing it unambiguously helps twice over.

Example​

A rule type the library does not know — the backend marks the SKU field with sku_format:

<SchemaAdmin
validatorProvider={({rule}) => {
if (rule.type === 'sku_format') {
return (value) => (isValidSku(value) ? undefined : rule.message ?? 'Invalid SKU');
}
}}
>
<SchemaResource name="eshop/product" />
</SchemaAdmin>

Overriding a built-in rule for one resource, and suppressing another one entirely:

<SchemaAdmin
validatorProvider={({rule, resource, source}) => {
if (resource === 'eshop/product' && source === 'description' && rule.type === 'max_length') {
return maxLength(rule.value as number, 'Product descriptions are capped at %{max} characters');
}
// The catalogue import writes prices the frontend must not block.
if (resource === 'eshop/price-import' && rule.type === 'max_value') {
return null;
}
}}
>
…
</SchemaAdmin>

When the rules run​

The generated form validates on blur, so a rule reports as soon as the field loses focus. To go back to validating on submit, pass mode="onSubmit" to FormShell.

See also​