Client script.
One script tag turns every plain HTML form on the page into an AJAX form: it submits with fetch, shows a status message, solves the ALTCHA challenge, passes captcha tokens and files through and follows your redirect. No dependencies, no bundler, no second external host.
Including it
The version is part of the URL. A future incompatible version ships as /client/v2/script.js, so a page pinned to v1 keeps working unchanged.
The script takes over every form whose action points at a Mailan submit endpoint — nothing else to initialise, and forms added to the page later are covered too.
Attributes on the form
| Attribute | Effect |
|---|---|
data-mailan="off" |
Opt this one form out; it submits classically again. |
data-mailan-altcha |
Fetch and solve an ALTCHA challenge before sending. |
data-mailan-success |
Text shown after a successful submission. |
data-mailan-error |
Fallback text when the request failed. |
data-mailan-state |
Set by the script: „sending", „success" or „error". Style on it. |
An element carrying data-mailan-message inside the form receives the status text. Without one the script appends a paragraph itself, so a form without any markup for it still gives feedback.
Events
Three events bubble from the form, each with the parsed response or the error in detail. That is the hook for your own analytics, a custom animation or a dialog.
Upload widget
A file input marked data-mailan-uploader gets a drop zone with a file list and remove buttons. Type, count and size are checked in the browser before anything is sent — the server limit stays the binding one.
| Attribute | Effect |
|---|---|
accept |
Allowed types: extensions, mime types, wildcards like image/*. |
data-max-files |
Maximum number of files. Above 1 the input becomes multiple. |
data-max-file-size |
Size per file, e.g. „5MB", „500kb" or a byte count. |
data-mailan-prompt |
Text inside the drop zone. |
data-mailan-remove-label |
Label of the remove button. |
A rejected file fires mailan:upload-rejected with the reason, so you can show it wherever it fits your design.
What it does on its own
- Without an upload it sends urlencoded instead of multipart — smaller, and captcha verification sees the fields.
- It disables the submit buttons while a request is in flight and releases them afterwards.
- A redirect field is taken out of the payload and navigated to by the script, because fetch cannot read a cross-origin 303.
- A captcha widget that is present but unsolved stops the submission with a message instead of a failed request.
- After success the form is reset — so a second message does not repeat the first.