Connect country, state and district choices

Load state suggestions from a country, then county or district choices from the selected state in your own form.

JavaScript (browser)Last tested Download and run ↓
On this page

Working example

HTML + form.js

Run the example

Download HTML

country-state-dropdown.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:

Terminal · Python 3
python3 -m http.server 8000

Open localhost:8000/country-state-dropdown.html. When publishing, add your website's hostname to the key. Keep secret keys on your server.

Need a key? Set up this example

Connect country, state and district

Connect a country dropdown to state and district fields without hardcoding their lists. Include form.js, mark the country selector, and bind the state input's native datalist to the returned states. Mark the state input with data-parse="state" and bind the district datalist to its districts response.

HTML
<script src="https://cdn.parseapi.com/v1/form.js" data-key="YOUR_PUBLIC_API_KEY" data-parse-version="2.1.0" 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>
    <option value="FR">France</option>
  </select>
</div>
<div class="field">
  <label for="state">State, province, or region</label>
  <input id="state" name="state" data-parse="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>
<div class="field">
  <label for="district">County or district</label>
  <input id="district" name="district" list="districts" autocomplete="off" placeholder="Choose or type a district">
  <datalist id="districts" data-parse-from="state" data-parse-fill="districts"></datalist>
</div>

The five 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.

Select a state

Choosing a state code loads its counties or districts through /state/{code}/districts?country=XX. The state field reads its country from the existing country-to-states connection. For a standalone state field, set an explicit data-parse-country="US" instead. The requests use the ordinary included API; no Deep option is needed.

District option values are stable codes, with names as labels. The current lists cover the US, France and Great Britain. Other countries can still load their states, while the editable district input remains available for manual entry.

Changing a state clears its previous district choices and a value selected from them. Changing the country also cancels the previous district lookup. A late response cannot fill choices for a different country or state. Manually typed district values remain editable; missing results and lookup failures do not add a submission block.

For native dropdowns, put data-parse="state" on the state select alongside its existing data-parse-from="country" data-parse-fill="states" binding. Use data-parse-from="state" data-parse-fill="districts" on the district select. Keep an empty placeholder option in each select. Use datalists, as in the download, when people should be able to enter a value that is not listed.

Submit the country alongside the state and district. The download's field names are country, state and district; adapt them to your server's input. Accept typed values according to your application's rules and validate the submitted combination 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.

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>Connect country, state and district choices</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" data-parse-version="2.1.0" 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>
        <option value="FR">France</option>
      </select>
    </div>
    <div class="field">
      <label for="state">State, province, or region</label>
      <input id="state" name="state" data-parse="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>
    <div class="field">
      <label for="district">County or district</label>
      <input id="district" name="district" list="districts" autocomplete="off" placeholder="Choose or type a district">
      <datalist id="districts" data-parse-from="state" data-parse-fill="districts"></datalist>
    </div>
    <!-- /example:form -->
  </main>
</body>
</html>

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

Build something else

All tutorials →