---
title: "Email validation in JavaScript: a form example | Emvero"
description: "Validate an email field with HTML and JavaScript, show useful errors, and know when to check the address on your server."
url: https://emvero.io/blog/email-validation-javascript/
language: en
updated: 2026-10-14
---

Blog

# Email validation in JavaScript: a working form example

Build an email field with clear errors, test its limits, and pass accepted input to your server for independent validation.

Published 2026-10-14

To validate an email address in JavaScript, use an HTML ` ` with `required`, then call `checkValidity()` to decide which feedback to show. A passing format check leaves domain, mailbox and ownership questions unanswered. See [MDN’s email-input reference](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/email).

## A form you can try in a browser

Save this example as an HTML file and open it in a browser. Enter one address and select Continue, or press Enter. The example displays the format result locally. Before using it for registration, connect the successful branch to your own server handler.

```
<form id="email-form" novalidate>
  <label for="email">Email address</label>
  <input id="email" name="email" type="email" autocomplete="email"
         required aria-describedby="email-feedback">
  <p id="email-feedback" aria-live="polite"></p>
  <button type="submit">Continue</button>
</form>

<script>
const form = document.querySelector("#email-form");
const email = document.querySelector("#email");
const feedback = document.querySelector("#email-feedback");

email.addEventListener("input", () => {
  feedback.textContent = "";
  email.removeAttribute("aria-invalid");
});

form.addEventListener("submit", (event) => {
  event.preventDefault();

  if (!email.checkValidity()) {
    const message = email.validity.valueMissing
      ? "Enter an email address."
      : email.validity.typeMismatch
        ? "Enter an address in email format."
        : "Check the email address.";

    feedback.textContent = message;
    email.setAttribute("aria-invalid", "true");
    email.focus();
    return;
  }

  email.removeAttribute("aria-invalid");
  feedback.textContent = "Format accepted. Send the address to your server.";
});
</script>
```

## How the example handles errors

`novalidate` suppresses automatic submit-time validation; the explicit `checkValidity()` call still runs. `valueMissing` identifies an empty required field, and `typeMismatch` identifies an email-format error. The [HTML constraint validation API](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#the-constraint-validation-api) defines these checks.

The label names the field. On an error, the code writes a specific message, sets `aria-invalid` and returns focus to the input. `aria-describedby` associates the feedback with the field, while `aria-live="polite"` makes changing feedback available to assistive technology. When the person edits the value, the code clears the previous message and invalid state so they can try again. Error feedback does not depend on colour.

If the browser’s own error messages suit your form, set the form to submit by POST to your server handler, then remove `novalidate` and the JavaScript submit handler. The HTML input already performs the format check; JavaScript is useful here because it controls the wording and placement of the feedback.

## Test the format check before connecting a server

Use the following inputs in the example. The results describe this form’s browser validation, without a network request.

| Input | Result in the example | What to check |
| --- | --- | --- |
| Empty field | Missing-value message | Focus returns to the field and `aria-invalid` is set |
| `alex.example.com` | Format-error message | A missing `@` is caught |
| `alex@example.com` | Format accepted | No address is submitted |
| `alex+orders@example.com` | Format accepted | The plus-tagged local part is preserved |
| `alex@example` | Format accepted | Browser acceptance does not establish a public mail route |
| `alex@example.com,pat@example.org` | Format-error message | This form accepts one address, without `multiple` |

After an error, correct the value and submit again. The old error and `aria-invalid` should clear. Test both the button and the Enter key, since either can submit the form.

The domains are synthetic: [RFC 2606 reserves `example.com` and `example.org` for documentation](https://www.rfc-editor.org/rfc/rfc2606.html). An accepted example cannot demonstrate a real mailbox.

## When a custom regex helps

For this form, keep the browser’s email rules and use JavaScript for feedback. A second regex adds another rule to maintain. If your application intentionally restricts addresses to one organisation’s domain, document that as a business requirement and enforce it on the server too.

Keep accepted addresses intact when handing them to the server. In the plus-address test, removing `+orders` would change the submitted value. This example covers one address under browser input rules; unusual or internationalised formats need a separate support decision and tests across the form, server parser and mail service.

## What to do after the browser accepts the format

Send the value to your application server over its normal form or API route. Validate submitted data independently there: a client can bypass browser checks and make a direct request. [MDN’s form-validation guide](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Form_validation) explains this boundary.

In the example, `event.preventDefault()` cancels submission. The success message is the point where you would add your application’s request. Check its response before advancing the flow, and show a recoverable error if the request fails. The local success message alone must not create an account or mark an address as verified.

Once the server has accepted the format, choose the next check according to the decision you need to make:

| Question | Appropriate next step | What it still cannot prove |
| --- | --- | --- |
| Is the text shaped like an email address? | Browser feedback plus independent server validation | Domain or mailbox existence |
| Can I use this address for a workflow? | Gather domain, mail-routing and, where available, recipient evidence through server-side verification | Guaranteed delivery or control of the mailbox |
| Does this person control the mailbox? | Send a confirmation link or code from your own application and require a response | Identity or future delivery |

The [syntax-versus-SMTP comparison](https://emvero.io/compare/smtp-vs-syntax-validation/) helps choose the depth of evidence. A full Emvero check can collect recipient-level SMTP evidence without sending a message. Server restrictions or timeouts can leave the answer `unknown`, which does not establish that the address is undeliverable. Call the [email verification API](https://emvero.io/email-verification-api/) from your server so its credentials remain private.

For a signup flow, use the [signup-form validation guide](https://emvero.io/guides/signup-form-validation/) to decide which results allow the person to continue and when to ask for confirmation.

## Terms used here

### Email address syntax

The format rules for an email address; passing them does not establish that the domain or mailbox exists.

### SMTP handshake

The command-and-reply exchange with a mail server; a mailbox check uses it to observe the server’s recipient response.

## Situations this applies to

### Validating an address in a signup form

Somebody is waiting on the other side of the request, so latency decides the design and a wrong rejection costs you the customer.

[All articles](https://emvero.io/blog/)

## Choose what to check next.

Run a check from your account and inspect the evidence in its result.

Start for free
