validate is a custom synchronous callback that decides whether an element’s current value is acceptable. It runs on every change (debounced), on blur (synchronous), and at submit time (synchronous).
Providing validate opts the element fully out of built-in validation. The callback owns the entire validity contract.
Signature
- Return
nullto signal the value is valid. - Return any non-empty string to surface a
FieldErrorwithcode: 'custom'and the returned string asmessage.
onChange.value:
card does not accept validate. submitButton, applePay, googlePay, and checkout also do not.
Example
Precedence: validate disables built-ins
When validate is supplied, the SDK skips all built-in checks for that element:
- The zod format schema (email format, address atom formats, and so on).
- Provider-level validity checks (for example, the phone element’s E.164 check).
- The built-in
requiredempty check.
null for empty inputs. This is intentional: “I provided validate, so I own this.”
To keep the built-in checks and layer business rules on top, leave validate unset and gate your business logic elsewhere (server-side, or inside your own onChange handler).
Debouncing
The callback runs debounced. The default delay is 250 ms. Tune it per-instance:submit(), so error snapshots are current when the shopper tabs away or submits.
Multi-field elements
ForbillingAddress, shippingAddress, and bank, the callback receives the whole-shape value:
required and format checks for atom-keyed errors.
Bank
validate on bank runs in manual mode only. In address-lookup mode, the SDK’s own lookup owns validity timing and skips the callback.
Async validation
validateAsync is reserved for a future release. Attempting to set it fails type-check today.
FieldError from validate
onChange.errors (live) or onError.fieldErrors (submit time).