How to validate a Wix form with Velo
Mosaddik Billah 3 min read

On this page
Wix inputs already handle the simple cases: you can mark a field as required, set a maximum length, or choose the email input type. For anything more specific, such as “the two email fields must match” or “the booking date can’t be in the past”, you need a few lines of Velo.
This guide adds custom checks to a booking form, shows a clear message when something is wrong, and repeats the important check on the backend.
The form#
The examples use these elements:
#emailand#confirmEmail: text inputs set to the email type#phone: a text input#date: a date picker#submitButton: the submit button, connected to a dataset#errorText: a text element, hidden on load
Start with the built-in settings: mark the required fields as Required in each input’s settings. Custom validation adds to these checks; it doesn’t replace them.
1. Add custom checks with onCustomValidation#
onCustomValidation runs your function whenever Wix checks an input. Call reject with a message to mark the input as invalid:
$w.onReady(() => {
$w("#confirmEmail").onCustomValidation((value, reject) => {
if (value.trim().toLowerCase() !== $w("#email").value.trim().toLowerCase()) {
reject("The email addresses don’t match.");
}
});
$w("#phone").onCustomValidation((value, reject) => {
const digits = value.replace(/[^\d]/g, "");
if (digits.length < 10 || digits.length > 15) {
reject("Please enter a phone number with country code.");
}
});
$w("#date").onCustomValidation((value, reject) => {
const today = new Date();
today.setHours(0, 0, 0, 0);
if (value && value < today) {
reject("Please choose today or a later date.");
}
});
});An input that fails a check gets Wix’s invalid style, and a dataset won’t save the form while any connected input is invalid.
2. Show the message to the visitor#
The invalid style alone doesn’t say what’s wrong. Each input’s validationMessage holds the text you passed to reject, so you can show the first problem in #errorText:
const fields = ["#email", "#confirmEmail", "#phone", "#date"];
function showFirstError() {
const invalid = fields.map((id) => $w(id)).find((input) => !input.valid);
if (invalid) {
$w("#errorText").text = invalid.validationMessage || "Please check the highlighted fields.";
$w("#errorText").show();
} else {
$w("#errorText").hide();
}
}
$w.onReady(() => {
// ...the onCustomValidation calls from step 1
$w("#submitButton").onClick(() => {
fields.forEach((id) => $w(id).updateValidityIndication());
showFirstError();
});
$w("#email").onChange(() => $w("#confirmEmail").updateValidityIndication());
});Two details matter:
updateValidityIndication()shows the invalid style even on fields the visitor hasn’t touched yet, so they can see every problem at once.- Re-checking
#confirmEmailwhen#emailchanges stops an old “don’t match” error from sticking after the visitor fixes the first field.
3. Repeat the important checks on the backend#
Page code runs in the visitor’s browser, so it can be skipped. Anything that really matters, like a valid date for a booking, should also be checked before the item is saved. In the backend folder, add a data hook to data.js:
export function Bookings_beforeInsert(item, context) {
const today = new Date();
today.setHours(0, 0, 0, 0);
if (!item.date || new Date(item.date) < today) {
return Promise.reject("The booking date must be today or later.");
}
item.email = item.email.trim().toLowerCase();
return item;
}Rejecting the promise stops the insert. The hook is also a good place to clean up data, such as lowercasing emails, so your collection stays consistent.
Tips for forms people finish#
- Keep messages specific and friendly. “Please choose today or a later date” is more useful than “Invalid input”.
- Ask only for what you need. Every extra field makes some visitors leave.
- Don’t over-validate names and addresses. Real names include apostrophes, hyphens and non-Latin letters.
- Test on a phone, with the keyboard open, before publishing.
If you need forms with custom logic, payments or connections to other tools, I do Wix Velo development.
Comments