Add city autocomplete to an existing field
Use form.js to suggest cities and keep the selected city ID with your form.
On this page
Working example
HTML + form.jsMark the city field
Include form.js, add data-parse="city", and bind a hidden field to the selected city's id. The visible field stays part of your form.
<script src="https://cdn.parseapi.com/v1/form.js" data-key="YOUR_PUBLIC_API_KEY" defer></script>
<div class="field">
<label for="city">City</label>
<input id="city" name="city" data-parse="city" data-parse-country="US" autocomplete="address-level2" placeholder="Start typing a city">
<input type="hidden" name="city_id" data-parse-from="city" data-parse-fill="id">
</div>Replace YOUR_PUBLIC_API_KEY with a Public key from the keys page. Allow your site's hostname and localhost for local development. Serve the downloaded HTML over HTTP; keep secret keys on your server.
This example narrows suggestions to the United States with data-parse-country="US". Set another country code when your form has that context, or omit the attribute to search without a country filter.
Choose the right place
Type at least two characters. The script shows city suggestions with region and country details so identically named places are easier to distinguish. Click one, or use the arrow keys and Enter. Escape closes the suggestions; Tab leaves the field without choosing one.
Selection fills the city name and its hidden ID. Editing the name clears that ID immediately. Unmatched text stays editable with an empty ID, and a search never silently chooses the first result.
Keep the ID when your application needs to retrieve the same place later. Validate submitted IDs on your server when the application relies on them; hidden fields are still browser input.
Build directly with the City API for a custom picker, additional filters, or lookup by the selected ID.
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>Add city autocomplete to an existing field</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-city-suggestions { margin: 6px 0 0; padding: 0; list-style: none; border: 1px solid var(--line); border-radius: 8px; background: var(--bg); color: var(--ink); font: inherit; overflow: hidden; }
.parse-city-suggestions li { padding: 10px 14px; cursor: pointer; overflow-wrap: anywhere; }
.parse-city-suggestions li + li { border-top: 1px solid var(--line); }
.parse-city-suggestions .street { display: block; font-weight: 500; }
.parse-city-suggestions .place { display: block; margin-top: 2px; color: var(--muted); font-size: .8em; }
.parse-city-suggestions li[aria-selected="true"], .parse-city-suggestions li:hover { background: color-mix(in srgb, var(--accent) 12%, var(--bg)); }
@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" defer></script>
<div class="field">
<label for="city">City</label>
<input id="city" name="city" data-parse="city" data-parse-country="US" autocomplete="address-level2" placeholder="Start typing a city">
<input type="hidden" name="city_id" data-parse-from="city" data-parse-fill="id">
</div>
<!-- /example:form -->
</main>
</body>
</html>
Need a key? Create a public API key. For every field and parameter, see City API reference.