Skip to content

Country Input

<quiet-country-input> stable since 6.1 form-associated This component is a form-associated custom element. It will submit its value when given a name and placed inside a <form>.

Lets users choose a country from an intuitive, searchable picker that integrates with native forms. Reach for it when you need a reliable country code, or just a friendlier picker than a huge select menu.

There's no single intuitive way to pick a country. Some users scan the list, some type the name, and some type the two-letter code. This component optimizes for all three, opening a dialog instead of a dropdown for a more comfortable experience. It even suggests a country based on the visitor's timezone and locale, so most see their country right at the top.

Country names are derived from the browser's Intl.DisplayNames data rather than a bundled list, so they render in the page's language and stay current with CLDR without library updates.

<quiet-country-input
  name="country"
  label="Country / Region"
  description="Search by name or code, then press Enter."
></quiet-country-input>

Examples Jump to heading

Labels and descriptions Jump to heading

Use the label and description attributes to provide plain text labels and descriptions. To provide HTML, use the label and description slots instead.

We only ship where our cats have friends. See the list.
<quiet-country-input name="ship-to" label="Ship to">
  <span slot="description">
    We only ship where our cats have friends. <a href="https://example.com/" target="_blank">See the list</a>.
  </span>
</quiet-country-input>

Providing an initial value Jump to heading

Use the value attribute to preselect a country. The value is a lowercase ISO 3166-1 alpha-2 code, such as us or jp.

<quiet-country-input name="origin" label="Country of origin" value="jp"></quiet-country-input>

The value property only holds the code. To get the selected country's resolved name and flag as well, call the getSelectedCountry() method.

Localizing the list Jump to heading

Country names and sort order follow the lang attribute, the same as every other translated string in Quiet. Set it on the <html> element or the host element and the list will update.

Sorting uses Intl.Collator, so names land where a reader of that language expects them. Open the English and Swedish pickers below and compare: Åland sorts near the top in English but at the very bottom in Swedish.

<div id="country-lang">
  <quiet-country-input lang="en" label="English" value="ax"></quiet-country-input>
  <quiet-country-input lang="sv" label="Svenska" value="ax"></quiet-country-input>
  <quiet-country-input lang="ja" label="日本語" value="ax"></quiet-country-input>
</div>

<style>
  #country-lang {
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }
</style>

Searching Jump to heading

Search matches a country's name in the current language, its name in English, and its two-letter code. Typing an English name works even when the interface is in another language.

Formal names work too. Searching for "united states of america" finds United States, and "republic of india" finds India. A handful of names people still type, such as Holland, Ivory Coast, and Czech Republic, are matched as well.

<quiet-country-input
  name="search-demo"
  label="Try searching"
  description="Try “holland”, “uae”, “ivory coast”, “deutschland”, or just “de”."
></quiet-country-input>

Adding your own search terms Jump to heading

If your audience searches for something the browser doesn't know about, add it with the aliases property. Terms you supply are matched alongside the built-in ones.

<quiet-country-input id="country-aliases" label="Custom aliases" description="Try “nederland” or “bharat”."></quiet-country-input>

<script>
  const countryInput = document.getElementById('country-aliases');

  countryInput.aliases = {
    nl: ['nederland'],
    in: ['bharat']
  };
</script>

aliases is a property, not an attribute, so it has to be set with JavaScript.

Country names and contested territories Jump to heading

Quiet renders country names from the CLDR verbatim and takes no editorial or political position: the entries are ISO 3166-1, and the names are derived from the browser's CLDR data. The list is sorted alphabetically for the current language, so no entry appears to rank above another.

CLDR's long forms carry wording some users may object to. You can use the names property to customize any country's display name.

<quiet-country-input id="country-names" label="Custom names" value="hk"></quiet-country-input>

<script>
  const named = document.getElementById('country-names');

  named.names = {
    hk: 'Hong Kong',
    mo: 'Macao',
    ps: 'Palestine'
  };
</script>

A name you set sorts and displays like any other, and the original name stays searchable, so users can still find the entry by typing the name they know.

To remove an entry entirely, use exclude. Together, names and exclude let you show exactly the list your jurisdiction or audience requires.

Only the 249 codes officially assigned by ISO 3166-1 are supported. Codes outside that set, including user-assigned ones such as xk for Kosovo, aren't available and can't be added with include.

Limiting the list Jump to heading

Use include to restrict the picker to a space-delimited list of codes, or exclude to remove codes from the full list. Both accept lowercase ISO 3166-1 alpha-2 codes.

<quiet-country-input
  name="nafta"
  label="Where should we deliver?"
  include="us ca mx"
></quiet-country-input>

Excluding is handy for dropping countries that shouldn't show up in the list, such as the uninhabited territories in this example.

<quiet-country-input
  name="billing"
  label="Billing country"
  exclude="aq bv hm gs tf um"
></quiet-country-input>

The suggestion Jump to heading

The picker suggests a country based on the device's timezone, falling back to the browser's locale when the timezone can't be resolved. This means most users will see their country at the very top of the list, making selection as easy as possible. Use without-suggestion to disable it.

<quiet-country-input
  name="no-suggestion"
  label="No suggestion"
  without-suggestion
></quiet-country-input>

Sizes Jump to heading

Use the size attribute to change the country input's size.

<div id="country-sizes">
  <quiet-country-input size="xs" label="Extra small" value="fr"></quiet-country-input>
  <quiet-country-input size="sm" label="Small" value="fr"></quiet-country-input>
  <quiet-country-input size="md" label="Medium" value="fr"></quiet-country-input>
  <quiet-country-input size="lg" label="Large" value="fr"></quiet-country-input>
  <quiet-country-input size="xl" label="Extra large" value="fr"></quiet-country-input>
</div>

<style>
  #country-sizes {
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }
</style>

Appearance Jump to heading

Use the appearance attribute to change the country input's appearance.

<div id="country-appearance">
  <quiet-country-input appearance="normal" label="Normal" value="br"></quiet-country-input>
  <quiet-country-input appearance="filled" label="Filled" value="br"></quiet-country-input>
  <quiet-country-input appearance="unstyled" label="Unstyled" value="br"></quiet-country-input>
</div>

<style>
  #country-appearance {
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }
</style>

Pill shape Jump to heading

Use the pill attribute to give the country input rounded edges.

<quiet-country-input pill label="Pill shape" value="ke"></quiet-country-input>

Clearing the selection Jump to heading

Like a native <select>, the control keeps its value once a country is chosen. Use the with-clear attribute on optional fields to add a clear button to the control and a matching action inside the picker.

<quiet-country-input
  name="optional-country"
  label="Country (optional)"
  description="Pick one, then use the clear button to empty the field again."
  value="pt"
  with-clear
></quiet-country-input>

Disabling Jump to heading

Use the disabled attribute to disable the country input.

<quiet-country-input
  label="Disabled country input"
  disabled
  value="it"
></quiet-country-input>

Read-only Jump to heading

Use the readonly attribute to make the country input read-only. The value stays visible, but the picker won't open.

<quiet-country-input
  label="Read-only country input"
  readonly
  value="it"
></quiet-country-input>

Validation Jump to heading

Use the required attribute to make the field required. Form submission won't be allowed until a country is selected.

Submit
<form action="about:blank" method="get" target="_blank" id="country-validation">
  <quiet-country-input name="country" label="Country" required></quiet-country-input>
  <quiet-button type="submit" variant="primary">Submit</quiet-button>
</form>

<style>
  #country-validation {
    display: flex;
    flex-direction: column;
    align-items: start;
    gap: 1rem;
  }
</style>

Using custom validation Jump to heading

Use the setCustomValidity() method to make the country input invalid and show a custom error message on submit. This will override all other validation parameters. To clear the error, remove the attribute or set it to an empty string.

Submit
<form action="about:blank" method="get" target="_blank" id="country-custom-validity">
  <quiet-country-input
    name="country"
    label="Country"
    description="This field will be invalid until custom validation is removed"
  ></quiet-country-input>
  <quiet-button type="submit" variant="primary">Submit</quiet-button>
</form>

<script type="module">
  import { allDefined } from '/dist/quiet.js';

  await allDefined();

  const form = document.getElementById('country-custom-validity');
  const countryInput = form.querySelector('quiet-country-input');

  countryInput.setCustomValidity('Not so fast, bubba!');
</script>

<style>
  #country-custom-validity {
    display: flex;
    flex-direction: column;
    align-items: start;
    gap: 1rem;
  }
</style>

Styling validation Jump to heading

You can style valid and invalid country inputs using the user-valid and user-invalid custom states. These styles are only shown after the user interacts with the form control or when the form is submitted. The :valid and :invalid pseudo classes are also available, but they match even before the user has had a chance to fill out the form.


Submit Reset
<form action="about:blank" method="get" target="_blank" id="country-validation-styles">
  <quiet-country-input
    name="country"
    label="Country"
    description="This field is required"
    required
  ></quiet-country-input>
  <br>
  <quiet-button type="submit" variant="primary">Submit</quiet-button>
  <quiet-button type="reset">Reset</quiet-button>
</form>

<style>
  #country-validation-styles {
    quiet-country-input:state(user-valid) {
      outline: solid 2px var(--quiet-constructive-stroke-mid);
      outline-offset: 0.5rem;
    }

    quiet-country-input:state(user-invalid) {
      outline: solid 2px var(--quiet-destructive-stroke-mid);
      outline-offset: 0.5rem;
    }
  }
</style>

If you're using the CSS utilities, add the quiet-user-valid and quiet-user-invalid classes to any form control for automatic validation styling.

Keyboard support Jump to heading

Tab to the country input and press Enter or Space to open the picker. Focus moves to the search field, and the keys below work from there without leaving it.

Key Action
+ Opens the picker from the trigger
Moves through the countries
Home End Jumps to the first or last country
Enter Selects the active country and closes the picker
Escape Closes the picker without changing the value

API Jump to heading

Importing Jump to heading

The autoloader is the recommended way to import components but, if you prefer to do it manually, the following code snippets will be helpful.

CDN Self-hosted

To manually import <quiet-country-input> from the CDN, use the following code.

import 'https://cdn.quietui.org/v6.0.0/components/country-input/country-input.js';

To manually import <quiet-country-input> from a self-hosted distribution, use the following code. Remember to replace /path/to/quiet with the appropriate local path.

import '/path/to/quiet/components/country-input/country-input.js';

Slots Jump to heading

Country Input supports the following slots. Learn more about using slots

Name Description
label The country input's label. For plain-text labels, you can use the label attribute instead.
description The country input's description. For plain-text descriptions, you can use the description attribute instead.

Properties Jump to heading

Country Input has the following properties that can be set with corresponding attributes. In many cases, the attribute's name is the same as the property's name. If an attribute is different, it will be displayed after the property. Learn more about attributes and properties

Property Description Reflects Type Default
label The country input's label. If you need to provide HTML, use the label slot instead. string
description The country input's description. If you need to provide HTML, use the description slot instead. string
name The name of the country input. This will be submitted with the form as a name/value pair. string
value The selected country as a lowercase ISO 3166-1 alpha-2 code, e.g. us. Empty when nothing is selected. string ''
placeholder The text to show in the trigger when no country is selected. string
disabled Disables the country input. boolean false
readonly Makes the country input read-only, so the picker can't be opened. boolean false
appearance The type of country input to render. 'normal' | 'filled' | 'unstyled' 'normal'
size The country input's size. 'xs' | 'sm' | 'md' | 'lg' | 'xl' 'md'
pill Draws the country input in a pill shape. boolean false
withClear
with-clear
Adds a button to the control that clears the selection, matching the other form controls that offer one, plus a matching clear action in the picker's footer. boolean false
form The form to associate this control with. If omitted, the closest containing <form> will be used. The value of this attribute must be an ID of a form in the same document or shadow root. string
required Makes the country input required. Form submission won't be allowed when this is set and no country is selected. boolean false
autofocus Tells the browser to focus the country input when the page loads or a dialog is shown. boolean
include Restricts the picker to a space-delimited list of ISO 3166-1 alpha-2 codes, e.g. us ca mx. When omitted, every country is shown. string
exclude Removes a space-delimited list of ISO 3166-1 alpha-2 codes from the picker, e.g. aq bv hm. string
withoutSuggestion
without-suggestion
Hides the suggestion that's derived from the visitor's timezone and browser locale. The suggestion is only ever a shortcut, so nothing is selected on the user's behalf. boolean false
aliases Additional search terms to match against, keyed by lowercase country code, e.g. { nl: ['nederland'] }. Use this to add names your audience types that CLDR doesn't know about. This is a property, not an attribute. Record<string, string[]> {}
names Replaces the displayed name for specific countries, keyed by lowercase country code, e.g. { hk: 'Hong Kong' }. Names otherwise come from the browser's CLDR data, whose wording some audiences contest. The name the browser would have shown stays searchable. This is a property, not an attribute. Record<string, string> {}

Methods Jump to heading

Country Input supports the following methods. You can obtain a reference to the element and call them like functions in JavaScript. Learn more about methods

Name Description Arguments
focus() Sets focus to the country input. options: FocusOptions
blur() Removes focus from the country input.
showPicker() Opens the picker.
hidePicker() Closes the picker.
getSelectedCountry() Returns the currently selected country, or undefined when the control is blank.
checkValidity() Checks if the form control has any restraints and whether it satisfies them. If invalid, false will be returned and the invalid event will be dispatched. If valid, true will be returned.
reportValidity() Checks if the form control has any restraints and whether it satisfies them. If invalid, false will be returned and the invalid event will be dispatched. In addition, the problem will be reported to the user. If valid, true will be returned.
setCustomValidity() Sets a custom validation message for the form control. If this message is not an empty string, then the form control is considered invalid and the specified message will be displayed to the user when reporting validity. Setting an empty string clears the custom validity state. message: string

Events Jump to heading

Country Input dispatches the following custom events. You can listen to them the same way was native events. Learn more about custom events

Name Description
quiet-blur Emitted when the country input loses focus. This event does not bubble.
quiet-change Emitted when the user commits a change to the country input's value.
quiet-focus Emitted when the country input receives focus. This event does not bubble.
quiet-input Emitted when the country input's value changes from user input. Selections commit in a single step, so this is always dispatched alongside quiet-change.

CSS custom properties Jump to heading

Country Input supports the following CSS custom properties. You can style them like any other CSS property. Learn more about CSS custom properties

Name Description Default
--picker-width The width of the picker dialog. 28rem
--picker-height The height of the picker dialog. 32rem

CSS parts Jump to heading

Country Input exposes internal elements that can be styled with CSS using the selectors shown below. Learn more about CSS parts

Name Description CSS selector
label The element that contains the country input's label. ::part(label)
description The element that contains the country input's description. ::part(description)
visual-box The element that wraps the internal trigger. ::part(visual-box)
text-box The internal trigger, a <button> element that opens the picker. ::part(text-box)
flag The selected country's flag, a <quiet-icon> element. ::part(flag)
clear-button The clear button, a <button> element. Only rendered when with-clear is set, a country is selected, and the control isn't disabled or read-only. ::part(clear-button)
chevron The chevron icon, a <quiet-icon> element. ::part(chevron)
chevron__svg The chevron icon's svg part. ::part(chevron__svg)
dialog The picker dialog, a <quiet-dialog> element. Only rendered after the picker first opens. ::part(dialog)
dialog__dialog The picker dialog's exported dialog part, the internal <dialog> element. ::part(dialog__dialog)
dialog__header The picker dialog's exported header part. ::part(dialog__header)
dialog__body The picker dialog's exported body part. ::part(dialog__body)
dialog__footer The picker dialog's exported footer part. ::part(dialog__footer)
search The picker's search field, an <input> element. ::part(search)
listbox The container that wraps the country options. ::part(listbox)
group The container that wraps a group of options and its heading. ::part(group)
group-label The heading above each group of options. ::part(group-label)
option An individual country option, a <button> element. ::part(option)
option-flag A country option's flag, a <quiet-icon> element. ::part(option-flag)
option-name A country option's name. ::part(option-name)
option-code A country option's ISO code. ::part(option-code)
option-check The check icon shown on the selected option, a <quiet-icon> element. ::part(option-check)
no-results The empty state shown when a search matches nothing. ::part(no-results)

Custom States Jump to heading

Country Input has the following custom states. You can target them with CSS using the selectors shown below. Learn more about custom states

Name Description CSS selector
disabled Applied when the country input is disabled. :state(disabled)
blank Applied when no country is selected. :state(blank)
open Applied when the picker is open. :state(open)
focused Applied when the country input has focus. :state(focused)
user-valid Applied when the control is valid and the user has sufficiently interacted with it. :state(user-valid)
user-invalid Applied when the control is invalid and the user has sufficiently interacted with it. :state(user-invalid)

Dependencies Jump to heading

Country Input automatically imports the following elements. Sub-dependencies are also included in this list.

Search this website Toggle dark mode View the code on GitHub Follow @quietui.org on Bluesky Follow @quiet_ui on X

    No results found