Skip to content

Events & instance API ​

Events ​

Every event is a CustomEvent dispatched on the form element. Events bubble, so you can listen on the form itself or once on document (where event.target is the form).

EventWhenevent.detailCancelable
submito:invalidClient validation failed. No request was sent{ errors: [{ name, message, field }], instance }No
submito:beforeRight before fetch, after captcha tokens and phone formatting were added{ formData, instance }Yes: preventDefault() cancels the request
submito:successA successful response arrived{ response, formData, instance }Yes: skips the built-in UI for this response
submito:errorAn error response, network failure or captcha failure{ response, formData, instance }Yes: skips the built-in UI for this response
submito:afterEverything is done and the buttons and indicator are restored{ response, formData, instance }No

Order for one submit: before → success or error → callback or built-in UI → after.

success / error fire whether or not you use callback. after does not fire when validation fails (invalid fires instead) or when before is cancelled.

What the user submitted ​

formData is the FormData object submito:before received, so it holds exactly what was sent: the form fields, your data values, the E.164 phone number with country / phone_code, and captcha tokens. It survives the reset that follows a successful submit, so prefer it over reading the form in after.

On a captcha failure the request is never sent, and formData is what would have been sent (without the token). It is null only if building the payload itself failed, for example when your data() function throws.

js
form.addEventListener('submito:success', (event) => {
  const { formData, response } = event.detail;
  console.log(`Thanks, ${formData.get('name')}!`, response.message);
});

Add fields right before sending ​

js
const form = document.querySelector('#contact');

form.addEventListener('submito:before', (event) => {
  event.detail.formData.set('timezone', Intl.DateTimeFormat().resolvedOptions().timeZone);
});

Ask for confirmation ​

js
form.addEventListener('submito:before', (event) => {
  if (!confirm('Send this message?')) event.preventDefault();
});

Analytics for every form on the page ​

js
document.addEventListener('submito:after', (event) => {
  analytics.track('form_submit', {
    form: event.target.id,
    success: event.detail.response.success,
    topic: event.detail.formData?.get('topic'),
  });
});

Framework-style listeners ​

Event names are lowercase, so they work with attribute-based listeners, for example Alpine.js:

html
<form id="contact" x-on:submito:success="sent = true">…</form>

Callback ​

callback(response, form) replaces the built-in response UI: no popup, no inline server errors, no reset. The events still fire, and it may return a Promise.

js
submito.newForm({
  form: '#contact',
  async callback(response, form) {
    if (response.success) {
      form.form.replaceWith(thankYouMessage(response.message));
      return;
    }
    const unmatched = form.showErrors(response.errors);
    showBanner([response.message, ...unmatched].filter(Boolean).join(' '));
  },
});

Client validation failures never reach the callback. They are always shown inline (listen for submito:invalid if you need to react).

Instance API ​

newForm() returns an instance:

MemberDescription
formThe HTMLFormElement
optionsThe resolved options
busytrue while a request is running
submit(submitter?)Validate and send, as if the user submitted. Resolves with the response object, or null if invalid, cancelled or already busy
validate()Validate all fields and show messages. Returns true when valid
showErrors(errors)Show errors inline. Accepts any error shape. Returns the messages that matched no field
clearErrors()Remove all inline errors
reset()form.reset() plus clearing errors, a new math captcha question, and a fresh Turnstile widget
destroy()Remove listeners, integration widgets and error markup. Use it when a form leaves the page
js
const form = submito.newForm({ form: '#wizard', responseType: 'none' });

const response = await form.submit();
if (response?.success) goToStep(3);

A <button type="reset"> or a call to form.form.reset() resets submito's state too.

Released under the MIT License.