Suggest states after choosing a country

Use form.js to connect a country selector to an editable state, province, or region field.

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

Working example

HTML + form.js
Use this example

Connect country and region

Include form.js and mark your country selector. Bind a native datalist to the returned states, then connect your region input to that list.

HTML
<script src="https://cdn.parseapi.com/v1/form.js" data-key="YOUR_PUBLIC_API_KEY" defer></script>
<div class="field">
  <label for="country">Country</label>
  <select id="country" name="country" data-parse="country" autocomplete="country">
    <option value="">Choose a country</option>
    <option value="US">United States</option>
    <option value="CA">Canada</option>
    <option value="GB">United Kingdom</option>
    <option value="AU">Australia</option>
  </select>
</div>
<div class="field">
  <label for="state">State, province, or region</label>
  <input id="state" name="state" list="states" autocomplete="address-level1" placeholder="Choose or type a region">
  <datalist id="states" data-parse-from="country" data-parse-fill="states"></datalist>
</div>

Replace YOUR_PUBLIC_API_KEY with a Public key from the example setup. Allow your site's hostname and localhost for local development. Serve the downloaded HTML over HTTP; keep secret keys on your server.

The four country choices are examples. Replace them with the countries your form accepts, keeping their two-letter codes as option values.

Select a country

Choosing a country loads its subdivisions. The region field offers their names and codes using the browser's native suggestions. Selecting one enters its subdivision code. Someone can also type a region directly, including when the lookup is unavailable.

Changing countries clears the previous suggestions and a region selected from them. Manually typed regions remain editable. A late lookup for the previous country cannot replace the current list, and typing during a request keeps that manual entry.

The list can contain states, provinces, territories, or other subdivisions. Choose the geographic level your application needs.

Submit the country alongside the region: short subdivision codes are not globally unique. Accept typed values according to your application's rules and validate the submitted pair on your server.

Build directly with the Country API when you need custom dropdown behavior or country details.

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
country-state-dropdown.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Suggest states after choosing a country</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, select { 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); }
    /* Keep native selection; size the closed control consistently in Safari. */
    select:not([multiple]):where(:not([size]), [size="0"], [size="1"]) {
      -webkit-appearance: none;
      appearance: none;
      padding-right: 40px;
      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='m4 6 4 4 4-4' fill='none' stroke='%2371717a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
      background-repeat: no-repeat;
      background-position: right 12px center;
      background-size: 16px;
    }
    :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
    .field + .field { margin-top: 18px; }
    /* 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; } }
  </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="country">Country</label>
      <select id="country" name="country" data-parse="country" autocomplete="country">
        <option value="">Choose a country</option>
        <option value="US">United States</option>
        <option value="CA">Canada</option>
        <option value="GB">United Kingdom</option>
        <option value="AU">Australia</option>
      </select>
    </div>
    <div class="field">
      <label for="state">State, province, or region</label>
      <input id="state" name="state" list="states" autocomplete="address-level1" placeholder="Choose or type a region">
      <datalist id="states" data-parse-from="country" data-parse-fill="states"></datalist>
    </div>
    <!-- /example:form -->
  </main>
</body>
</html>

Need a key? Set up this browser example. For every field and parameter, see Country API reference.

Build something else

All tutorials →