Autofill city and state from a ZIP code
Autofill editable city and state fields from a US ZIP code in your existing HTML form.
On this page
Working example
HTML + form.jsRun the example
Download HTMLzip-code-autofill.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/zip-code-autofill.html. When publishing, add your website's hostname to the key. Keep secret keys on your server.
Connect the three fields
A US ZIP code can save someone two fields of typing. Include form.js, mark your ZIP input, and connect the city and state fields to its answer. data-parse-from="postal" names the source input; data-parse-fill names the response field to fill.
<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="postal">US ZIP code</label>
<input id="postal" name="postal" data-parse="postal" data-parse-country="US" inputmode="numeric" autocomplete="postal-code" maxlength="5" placeholder="90210">
</div>
<div class="row">
<div class="field">
<label for="city">City</label>
<input id="city" name="city" data-parse-from="postal" data-parse-fill="city" autocomplete="address-level2">
</div>
<div class="field">
<label for="state">State</label>
<input id="state" name="state" data-parse-from="postal" data-parse-fill="state" autocomplete="address-level1">
</div>
</div>The ZIP stays text, so leading zeroes survive. inputmode="numeric" offers a numeric keyboard. data-parse-country="US" makes this example's country explicit.
Enter a complete ZIP
Type five digits and pause. The script fills the primary city and state for that ZIP. There is no lookup button, and a partial ZIP does not make a request.
City and state remain editable. Correct either field when needed; a pending response will not replace a manual correction. Changing the ZIP clears old generated values so they do not describe the previous code. Missing details stay blank, and unavailable lookups leave manual entry available.
Try 90210, then edit the city yourself and change the ZIP. The generated fields should clear when the ZIP changes. The download submits the fields as postal, city, and state; keep those names or use the names your server expects.
A ZIP lookup does not verify postal delivery to a street address. Build directly with the Postal API for a custom integration or other postal-code coverage.
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>Autofill city and state from a ZIP code</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; }
.field + .field { margin-top: 18px; }
.row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin-top: 18px; }
.row .field { margin-top: 0; }
/* 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); }
@media (max-width: 380px) { body { padding: 18px; } .row { grid-template-columns: 1fr; } }
</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="postal">US ZIP code</label>
<input id="postal" name="postal" data-parse="postal" data-parse-country="US" inputmode="numeric" autocomplete="postal-code" maxlength="5" placeholder="90210">
</div>
<div class="row">
<div class="field">
<label for="city">City</label>
<input id="city" name="city" data-parse-from="postal" data-parse-fill="city" autocomplete="address-level2">
</div>
<div class="field">
<label for="state">State</label>
<input id="state" name="state" data-parse-from="postal" data-parse-fill="state" autocomplete="address-level1">
</div>
</div>
<!-- /example:form -->
</main>
</body>
</html>
Need a key? Set up this browser example. For every field and parameter, see Postal API reference.
Build something else
- Choose an Australian suburb from a postcode
- Find nearby ZIP codes
- Calculate distance between ZIP codes
- Find an open store nearby
- Add places to a ZIP-code CSV
- Build a local weather card