Check an email as someone types
Add email validation and optional typo corrections to an existing HTML input with form.js.
On this page
Working example
HTML + form.jsRun the example
Download HTMLcheck-email-before-submit.html
Replace YOUR_PUBLIC_API_KEY in the downloaded file with your public key. Add localhost to that key's allowed domains. In a terminal in the download folder, run:
python3 -m http.server 8000Open localhost:8000/check-email-before-submit.html. When publishing, add your website's hostname to the key. Keep secret keys on your server.
Mark your email field
Add email validation to an existing HTML field with one script include and data-parse="email". Keep the field's label, name, and native HTML rules.
<script src="https://cdn.parseapi.com/v1/form.js" data-key="YOUR_PUBLIC_API_KEY" data-parse-version="2.0.0" defer></script>
<div class="field">
<label for="email">Email</label>
<input id="email" type="email" name="email" data-parse="email" autocomplete="email" placeholder="you@example.com" required>
</div>The script checks a complete-looking address after a typing pause or when the field loses focus. For a likely typo, such as hello@gmail.con, it offers a spelling correction beside the field. The person chooses whether to accept it.
Keep submission yours
The default preset marks an invalid format, an explicitly invalid mail domain, or a disposable address as invalid through the browser's native form validation. An unknown domain is not a failed check. Your required and type="email" rules still apply.
The script never waits for a pending lookup before submission. If the request is unavailable, it leaves the field unchecked. Your server must validate the submitted value and apply your signup rules.
Change the address after a check and confirm the old feedback clears. Format and domain checks help with entry; use server email verification when your workflow needs a delivery check. Ownership still needs your own confirmation flow.
For your own validation policy, data-parse-validation="manual" leaves custom validity to your code. Build directly with the Email API when you need a custom integration.
Complete example
One HTML file with your fields, styles, and the form.js include. Replace YOUR_PUBLIC_API_KEY with your public key, then run it on a domain you have added to that key.
View and copy the complete source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Check an email as someone types</title>
<style>
:root { color-scheme: light dark; --bg: #fff; --ink: #152029; --muted: #5e6b75; --line: #d9e2e7; --field: #f6f9fa; --accent: #007c91; --error: #b42335; }
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) { --bg: #0b1015; --ink: #eff7fa; --muted: #94a6b2; --line: #2c3942; --field: #121b23; --accent: #67e8f9; --error: #fda4af; }
}
:root[data-theme="dark"] { color-scheme: dark; --bg: #0b1015; --ink: #eff7fa; --muted: #94a6b2; --line: #2c3942; --field: #121b23; --accent: #67e8f9; --error: #fda4af; }
:root[data-theme="light"] { color-scheme: light; }
* { box-sizing: border-box; }
[hidden] { display: none !important; }
body { margin: 0; padding: 24px; background: var(--bg); color: var(--ink); font: 15px/1.5 system-ui, sans-serif; }
main { max-width: 540px; margin: 0 auto; }
label { display: block; margin-bottom: 8px; font-size: 14px; font-weight: 600; }
input { display: block; width: 100%; min-width: 0; padding: 13px 14px; border: 1px solid var(--line); border-radius: 8px; background: var(--field); color: var(--ink); font: inherit; }
input::placeholder { color: var(--muted); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Your form owns these styles. form.js adds semantic markup and states. */
input[data-parse-status="invalid"], input[data-parse-status="disposable"] { border-color: var(--error); }
.parse-hint { margin: 6px 0 0; color: var(--muted); font-size: .875em; line-height: 1.4; overflow-wrap: anywhere; }
.parse-hint[data-parse-status="invalid"], .parse-hint[data-parse-status="disposable"] { color: var(--error); }
.parse-hint-suggestion { padding: 0; border: 0; background: none; color: inherit; font: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.parse-hint-suggestion:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
@media (max-width: 380px) { body { padding: 18px; } }
</style>
</head>
<body>
<main>
<!-- example:form -->
<script src="https://cdn.parseapi.com/v1/form.js" data-key="YOUR_PUBLIC_API_KEY" data-parse-version="2.0.0" defer></script>
<div class="field">
<label for="email">Email</label>
<input id="email" type="email" name="email" data-parse="email" autocomplete="email" placeholder="you@example.com" required>
</div>
<!-- /example:form -->
</main>
</body>
</html>
Need a key? Set up this browser example. For every field and parameter, see Email API reference.