Autofill City & State from Zip Code with Ziptastic

Chris Coyier //

Most address fields on web forms ask for city, state, and zip code (or city and post code, outside of the US). But as us nerds often lament, city and state are redundant with zip code. Or at least they can be inferred from a correctly entered zip code. That's the kind of thing computers are good at. What we need is a proper API to cough up that information for us on demand.

Enter Ziptastic, a free (donations welcome) API for just that.

Let's use it.

Form Markup

Five fields. Two for street then city, state, and zip. All wrapped up in a form and fieldset. Nothing special.

<form action="#" method="post" class="fancy-form">

  <fieldset>
    <legend>Address</legend>

    <div>
      <div>
        <input type="text" name="address-line-1" id="address-line-1">
        <label for="address-line-1">Street #1</label>
      </div>
    </div>
    <div>
      <div>
        <input type="text" name="address-line-2" id="address-line-2">
        <label for="address-line-2">Street #2</label>
      </div>
    </div>
    <div>
      <div class="city-wrap">
        <input type="text" name="city" id="city">
        <label for="city">City</label>
      </div>
       <div class="state-wrap">
        <input type="text" name="state" id="state">
        <label for="state">State</label>
      </div>
       <div class="zip-wrap">
        <input type="text" pattern="[0-9]*" name="zip" id="zip">
        <label for="zip">Zip</label>
        <p class="zip-error">Not a real zip code.</p>
      </div>
    </div>

    <div>
      <input type="submit" value="Submit">
    </div>

  </fieldset>

</form>

Only show the zip at first

We'll hide all the divs that wrap each row of form elements. We'll use JavaScript, so that in case the user has JavaScript turned off, the form is still usable.

$(".fancy-form div > div").hide();

Then reveal just the zip code.

form .zip-wrap {
  display: block !important;
}

Front end validation

On the front end, we're already doing the best we can to help the proper entry of a zip code through HTML5 input attributes pattern, maxlength, and required.

<input type="text" pattern="[0-9]*" maxlength="5" required name="zip" id="zip">

Notice it's not of type number. Whenever considering type=number, consider "would I be cool with the browser adding commas inside of this number?" and if it's no, don't use it, because some do.

jQuery: Watch for entry of valid zip code

We're going to watch the zip input for keystrokes. Should the final value after a keystroke be a valid zipcode, we'll attempt to get the city and state through Ziptastic and reveal the other fields.

$("#zip").keyup(function() {
  var el = $(this);

  if ((el.val().length == 5) && (is_int(el.val()))) {
   
    // Make Ajax call, etc
 
  }

}

The is_int function is just some extra protection that the number is an integer (like all zip codes) in case the current browser doesn't support the necessary HTML5.

function is_int(value){ 
  if ((parseFloat(value) == parseInt(value)) && !isNaN(value)) {
      return true;
  } else { 
      return false;
  } 
}

jQuery: Ajax the data

Yeah so jQuery. We used it above to make event handling on the input easier, but it's really need here because of its ability to make ajax calls with error handling sixty two times easier than doing it with vanilla JavaScript.

After the passed validation, we can make the Ajax call. All we give it for data is the zip code we've collected and we get some JSON back which is trivially easy to access the city and state and apply them as values to the appropriate inputs.

$.ajax({
  url: "http://zip.elevenbasetwo.com",
  cache: false,
  dataType: "json",
  type: "GET",
  data: "zip=" + el.val(),
  success: function(result, success) {

    $(".fancy-form div > div").slideDown(); /* Show the fields */

    $("#city").val(result.city); /* Fill the data */
    $("#state").val(result.state);

    $(".zip-error").hide(); /* In case they failed once before */

    $("#address-line-1").focus(); /* Put cursor where they need it */

  },
  error: function(result, success) {

    $(".zip-error").show(); /* Ruh row */

  }

});

Of course we can validate all day long for the valid format of zip codes, but not every 5 digit integer is a zip code. Should we ask Ziptastic for a zip code that doesn't exist, it will return an error. In that case we just show an error message.

Demo and Download

View Demo   Download Files

Snag the ZIP. GET IT?! Also, if someone wants to apply some actually nice UX and design to this, I'd be happy to update the demo with credit. Andru Stoicescu at Better <html> submitted a bit of a fancier design so I updated to that.

Notes

  • I'm not going to tell you this is bulletproof. Addresses are hard. I heard some zip codes cross state lines.
  • Ziptastic is US only. Just days after publishing this, Ziptastic starts supporting postal codes internationally. Zippopotamus is similar and supports 60 counties.