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.jsRun the example
Download HTMLcity-autocomplete.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/city-autocomplete.html. When publishing, add your website's hostname to the key. Keep secret keys on your server.
Mark the city field
Add city autocomplete to a location or signup form. Include form.js, mark the city input with data-parse="city", and keep the selected city's id in a hidden field.
<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="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>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.
Try selecting a suggestion, then editing its name: city_id should clear while the text stays editable. Keep the selected ID when your application needs to retrieve that 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.
Build a custom component
For a component that talks directly to the API, open the complete City search example. Enter your own domain-restricted public key. The example waits 300 milliseconds after typing, cancels the previous request and ignores responses from older searches. It supports keyboard selection and native input composition. Editing the city clears its selected id.
A 429 response clears the choices and respects Retry-After before another search. It never automatically retries an old query. Keep the same rule in your own component: only the latest input may update the choices. The example requests format=list and selected fields; each result retains its id and object. See the City response reference.
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" data-parse-version="2.0.0" 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? Set up this browser example. For every field and parameter, see City API reference.