What if someone signs up for your web app and they type in their email address as susan_smith@gmaoil.com? They don't notice, they never get their confirmation email, they never can log in again, the "forgot password" feature doesn't work, and there is a lot of frustration and finger pointing.

Can't we help with that?

I had a really basic idea to suggest common email domains with a <datalist> suggestion dropdown. Essentially like this:

Datalists like that can be attached to any text-y input and they essentially provide suggestions. The user can still type in whatever valid value they want. It's like a cross between a <select> and and <input>, I suppose.

Here's how it works.

The Markup

Perfectly normal HTML that will work whether or not is supported or our JS runs or anything.

<label for="email">Email</label>
<input id="email" name="email" type="email" placeholder="your@email.com">

Inserting the datalist with JavaScript

Datalist is an HTML element, but we can't put it in the markup straight away because we don't know what to put in it yet. The options we put in there will need to have the first part of the email address in them. That's JavaScript territory, so we might as well only add the datalist when JavaScript runs.

jQuery, because I like it.

// Create empty datalist and append to DOM
var datalist = $("<datalist />", {
  id: 'email-options'

// Correlate to input
$("#email").attr("list", "email-options");

The Email TLD's

There are a handful of very popular "Top Level Domains" for email. Let's put them in an array:

var domains =  ["yahoo.com", "gmail.com", "google.com", "hotmail.com", "me.com", "aol.com", "mac.com", "live.com", "comcast.com", "googlemail.com", "msn.com", "hotmail.co.uk", "yahoo.co.uk", "facebook.com", "verizon.net", "att.net", "gmz.com", "mail.com"];

Adjust as needed.

Watching for Keystrokes

We don't want to bug the user until they have pressed the "@" key and we know they are moving on to the domain part of their email address. So first, we watch for the key event:

$("#email").on("keyup", function() {


Then we test to see if the value contains the @:

$("#email").on("keyup", function() {

  var value = $(this).val();
  if (value.indexOf("@") != -1) {
    // it's there, update datalist


We'd Better Get Organized

As this gets more complex, the more we should worry about spaghetti code and generally hard to maintain messiness. Let's get organized using an object to keep it all together.

The structure becomes basically:

var EmailDomainSuggester = {
  domains: ["yahoo.com", "gmail.com", "google.com", "hotmail.com", "me.com", "aol.com", "mac.com", "live.com", "comcast.com", "googlemail.com", "msn.com", "hotmail.co.uk", "yahoo.co.uk", "facebook.com", "verizon.net", "att.net", "gmz.com", "mail.com"],
  bindTo: $('#email'),
  init: function() {
  addElements: function() {
    // Create empty datalist
    this.datalist = $("<datalist />", {
      id: 'email-options'
    // Corelate to input
    this.bindTo.attr("list", "email-options");
  bindEvents: function() {
    this.bindTo.on("keyup", this.testValue);
  testValue: function(event) {
    var el = $(this),
        value = el.val();
    // remove the != -1 if you want the datalist to show up immediately as you type the @
    // with it in place, it won't show up until you type the NEXT character
    if (value.indexOf("@") != -1) {
       value = value.split("@")[0];
  addDatalist: function(value) {


Building the datalist on-the-fly

Notice in the above code I slipped in a little bit where I split the value that we pulled out of the input at the @ symbol. That allows us to pull out the part of the email address before the domain. For instance, the "chriscoyier" part of "chriscoyier@gm". Then we pass that over to a new function called addDatalist. Now let's use it:

// variables for iteration and string concatination
var i, newOptionsString = "";

// loop over all the domains in our array
for (i = 0; i < this.domains.length; i++) {
  newOptionsString += 
    "<option value='" + 
      value + 
      "@" +
      this.domains[i] +

// add all the <option>s to our datalist

Remove the datalist if we aren't ready for it

As a final bit of cleanup, we should remove the datalist if the value in the input doesn't have an @ symbol yet. Even if the user originally typed it but then backed up. We can handle that in our testValue function. We either update the datalist with the latest and greatest, or we remove it all together:

if (value.indexOf("@") != -1) {
  value = value.split("@")[0];
} else {
  // empty list

Final Demo

Rather than paste a huge chunk of code here, you can check it out in the Pen:

See the Pen Help Complete Email Addresses with by Chris Coyier (@chriscoyier) on CodePen

A More Robust Solution

For the record, I'm not absolutely sure the datalist approach is a great idea. It would require some real UX testing to see if it's actually helpful. It may be hurtful in the form of user confusion. I am more sure that some form of email domain checking is a good idea.

There is an open source project on GitHub called mailcheck.js that looks pretty good.

I suspect this "Did you mean" UX approach is smarter.

jquery.email-autocomplete.js is another option.


Have you used something like this? What do you think about the approaches? Have you done any UX testing around this or similar ideas? Do you have any other ideas to approach the "wrong email" problem?