Skip to content

Validation ​

submito validates in the browser before anything is sent. The rules come from the HTML you already write. Failed checks show inline messages, focus the first invalid field, fire submito:invalid, and skip the request.

Not a security boundary

Anyone can bypass browser checks or call your endpoint directly. Always validate again on the server. See Security.

Rules ​

HTMLMessage keyDefault message
required (whitespace-only counts as empty)requiredThis field is required.
type="email" (also multiple)emailPlease enter a valid email address.
type="url"urlPlease enter a valid URL.
type="number" with non-numeric inputnumberPlease enter a valid number.
minlength="8"minlengthPlease enter at least {min} characters.
maxlength="200"maxlengthPlease enter no more than {max} characters.
min="18" (numbers, dates)minPlease enter a value of {min} or more.
max="120"maxPlease enter a value of {max} or less.
step mismatch, unparsable datesinvalidPlease enter a valid value.
pattern="…"pattern, or the field's titlePlease match the requested format.
intl-tel-input numberphonePlease enter a valid phone number.
name="numb_captcha"captchaIncorrect answer. Please try again.

Checks run in that order. Only the first failing rule is shown. Disabled, readonly and hidden fields, and fields without a name, are skipped.

Custom message per pattern ​

The title attribute becomes the message for pattern:

html
<input name="username" pattern="[a-z]{3,12}" title="Use 3–12 lowercase letters." />

Change the wording ​

Override any message for one form with messages (see Internationalization):

js
submito.newForm({
  form: '#signup',
  messages: {
    required: 'Required',
    minlength: 'At least {min} characters, please.',
  },
});

Custom rules with setCustomValidity ​

Anything you set with the standard setCustomValidity() API is shown like a built-in rule:

js
const confirm = document.querySelector('[name="password_confirm"]');
confirm.addEventListener('input', () => {
  const same = confirm.value === document.querySelector('[name="password"]').value;
  confirm.setCustomValidity(same ? '' : 'Passwords do not match.');
});

Attach the listener to the field itself. It then runs before submito's listener on the form, so submito sees the updated validity.

When validation runs ​

On submit. Every field is checked and the first invalid one is focused.

While the user works on the form (liveValidation: true, the default):

  1. Nothing is flagged while someone types into a field for the first time.
  2. When they leave a field they changed (or pick an option, or toggle a checkbox), that field is checked.
  3. After that, the field is re-checked on every keystroke. Errors disappear as soon as the value is fixed.
  4. After a submit attempt, every field is re-checked on every keystroke.

Tabbing through an empty field does not show an error. Resetting the form clears all messages and starts over.

Set liveValidation: false to validate only on submit.

Validate from code ​

js
const form = submito.newForm({ form: '#checkout' });

nextStepButton.addEventListener('click', () => {
  if (form.validate()) goToNextStep();
});

validate() shows the messages, focuses the first invalid field, and returns true when everything passes.

Server-side errors ​

Messages returned by your API are shown next to the matching field in the same way. See Server responses. They are cleared when the user edits the field, or on the next submit.

Released under the MIT License.