Country Input
<quiet-country-input>
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
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.
<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
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 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.
<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.
<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.
<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.
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.