Add city autocomplete to an existing field

Use form.js to suggest cities and keep the selected city ID with your form.

JavaScript (browser)Last tested Get the complete example ↓
On this page

Working example

HTML + form.js

Mark 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.

HTML
<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.

Download HTML
View and copy the complete source
city-autocomplete.html
<!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.