
CountrySelect Pro is a vanilla JavaScript country selector that creates a searchable dropdown with SVG flags, ISO country codes, and international calling codes.
It supports custom country lists, localized names, keyboard navigation, Bootstrap 5 styling, and a form-associated Web Component.
You can use it with a text input, a native <select>, or <country-select>.
Features:
- Filter countries by name, ISO code, phone code, or search alias.
- Display SVG flags and preferred countries at the top of the list.
- Load custom countries from arrays, inline JSON, or a URL.
- Translate country names through
Intl.DisplayNames. - Use native form validation and keyboard-accessible controls.
- Open the dropdown above modal and overflow containers with the Popover API.
- Customize Bootstrap 5 and plain CSS themes with CSS variables.
- Initialize fields automatically after htmx updates and DOM changes.
Use Cases:
- Choose shipping or billing countries in checkout forms.
- Collect country codes in account registration and address forms.
- Select international calling prefixes alongside a telephone field.
- Enhance existing
<select>fields while retaining their HTML options.
How To Use It:
1. Install CountrySelect Pro
Load the browser build from a CDN.
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/country-select.min.js" defer></script>
For a strict Content Security Policy that blocks injected styles, load the packaged CSS before the script. The dropdown arrow uses an SVG data: URL, which requires img-src data:; flags use jsDelivr unless you configure baseUrl.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/country-select.min.css"> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/country-select.min.js" defer></script>
For npm projects, install the package and use its ES module build. The CSS import is optional when injected styles are permitted.
npm install country-select-pro
import CountrySelect from 'country-select-pro'; // Optional when using the packaged stylesheet: import 'country-select-pro/css';
2. Create a Searchable Country Field
The country-select class enables automatic initialization. Set an initial ISO code through the input value.
<label for="country">Country</label> <input id="country" class="country-select" name="country" value="GR" required>
Set data-value-type="phone" to store a calling prefix, or data-value-type="name" to store the country name.
<input class="country-select" name="dial_code" value="+30"
data-value-type="phone" data-schema-return="{img} {phone}">3. Initialize Manually
Pass an existing input, select element, or CSS selector to new CountrySelect(element, options). The optional second argument overrides the element’s data-* configuration and global defaults.
const picker = new CountrySelect('#country', {
defaultCountry: 'GR',
preferredCountries: ['GR', 'CY', 'DE'],
lang: 'el'
});
picker.ready.then(() => console.log(picker.getCountry()));4. Use the Web Component
The <country-select> custom element submits its selected value as a form field. It supports required, disabled, readonly, form reset, and associated labels.
<form>
<label for="shipping-country">Shipping country</label>
<country-select id="shipping-country" name="country" value="GR"
preferred="GR,CY" required></country-select>
<button type="submit">Submit</button>
</form>5. Enhance an Existing Select
An HTML <select> retains its own options before JavaScript runs. CountrySelect Pro enhances it when the script loads. Each option can also use data-code, data-phone, and data-flag to supply custom country details.
<select class="country-select" name="shipping_country" required> <option value="">Choose a country</option> <option value="GR">Greece</option> <option value="CY" selected>Cyprus</option> <option value="DE">Germany</option> </select>
6. Load Custom Countries
Use data-countries for an inline JSON list or data-src for a JSON endpoint. The default merge: true fills missing details for recognized ISO codes.
<input class="country-select" data-countries='["GR","CY","IT"]'> <input class="country-select" data-src="/api/shipping-countries.json">
The JavaScript countries option accepts an array, JSON string, URL, Promise, or function returning a list. Use setCountries() to replace the list later.
const picker = new CountrySelect('#country', {
countries: () => fetch('/api/countries').then(response => response.json())
});
picker.ready.then(() => picker.setCountries(['GR', 'CY', 'IT']));Supported list shapes include arrays of ISO codes or objects, {countries: [...]}, {items: [...]}, {data: [...]}, {results: [...]}, and maps such as {"GR": "Greece"}.
| Custom item field | Meaning |
|---|---|
code | ISO code. Aliases: iso2, iso, alpha2. |
name | Displayed label. Aliases: label, text. |
phone | Calling code. Aliases: dial_code, dialCode. |
flag | Flag image URL or false. |
value | Custom submitted value. |
keywords | Extra searchable words, as a string or array. |
aliases | Alias for keywords. |
Configuration Options:
Set options through JavaScript, input data-* attributes, or window.CountrySelectConfig. Precedence is: constructor options, element attributes, global configuration, built-in defaults.
valueType(data-value-type):'code'(default),'phone', or'name'. Determines the value saved in the form field.schema(data-schema): Country list item template. Default{img} {name}; placeholders:{img},{name},{code},{phone}.schemaReturn(data-schema-return): Template for the selected value. Defaults toschema.preferredCountries(data-preferred): Array or comma-separated ISO codes shown at the beginning of the dropdown.onlyCountries(data-only-countries): Array or comma-separated ISO codes allowed in the list.excludeCountries(data-exclude-countries): Array or comma-separated ISO codes omitted from the list.defaultCountry(data-default-country): ISO code used when the field has no initial value.placeholder(data-placeholder): Unselected-field text. English default:Select.search(data-country-search): Boolean; enables the search input. Defaulttrue.searchPlaceholder(data-search-placeholder): Search input text. English default:Search....noResults(data-no-results): Message for an empty search. English default:Not found.loading(JavaScript/global configuration): Loading message. English default:Loading....loadError(JavaScript/global configuration): Error message for an unavailable list. English default:Could not load the list.results(JavaScript/global configuration): Screen-reader plural result count. English default:{n} results.result(JavaScript/global configuration): Screen-reader singular result count. English default:{n} result.listLabel(JavaScript/global configuration): Accessible list name when the field has no label. English default:Countries.rows(data-country-row-values): Number of visible dropdown rows. Default5.dropdownWidth(data-dropdown-width): CSS width for the dropdown, such as300px. Defaultauto.popover(data-popover): Boolean; uses the Popover API top layer when available. Defaulttrue;falsekeeps the list in-page.lang(data-lang): Language for country names and UI text, such aselorde;autoreads the page language.flags(data-flags): Boolean; shows flag icons. Defaulttrue.sort(data-sort): Boolean; sorts countries by name. Defaulttrue;falsepreserves custom list order.countries(data-countries): Custom country source. Attribute takes inline JSON; JavaScript accepts arrays, objects, strings, Promises, or functions.dataUrl(data-src): URL for a JSON country list.fetchOptions(JavaScript/global configuration):RequestInitoptions passed tofetch()fordataUrl.merge(JavaScript/global configuration): Boolean; fills missing custom-country details from the built-in list. Defaulttrue.baseUrl(data-base-url): Base folder for hosted flag assets. Defaults to this version of the package on jsDelivr.flagPath(data-flag-path): Flag image URL template. Default{baseUrl}dist/flags/4x3/{code}.svg; use{code}for lowercase or{CODE}for uppercase.
Global Configuration
Declare global defaults before the browser script. The additional global options css and autoInit both default to enabled. Set either to false to disable injected CSS or automatic initialization.
<script>
window.CountrySelectConfig = {
preferredCountries: ['US', 'CA'],
lang: 'en',
baseUrl: '/vendor/country-select-pro/'
};
</script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/country-select.min.js" defer></script>Methods And Public Properties:
Constructor and Static API
| Signature / property | Description |
|---|---|
new CountrySelect(element, options?) | Create or configure a picker for an input, select, or CSS selector. options is optional. |
CountrySelect.init(root?) | Initialize fields with .country-select inside a root element or document; default root is document. |
CountrySelect.getInstance(element) | Get the current picker instance for a selector, input, select, or <country-select>; returns null when absent. |
CountrySelect.version | Library version. |
CountrySelect.baseUrl | Default folder for flag assets. |
CountrySelect.defaults | Global default configuration. |
CountrySelect.Element | Custom element constructor, or null where unavailable. |
Instance API
| Method / property | Description |
|---|---|
open() | Open the dropdown. |
close(refocus?) | Close the dropdown; pass true to return focus to the control. |
toggle() | Toggle dropdown visibility. |
setValue(value, {silent?}) | Select a value; dispatches change, input and country-change unless silent: true. Returns the instance. |
getValue() | Return the current form field value. |
getCountry() | Return {code, name, localName, phone, value} or null. |
setCountries(source) | Replace the country source and load the new list. Returns a Promise. |
refresh() | Synchronize the widget after changing input.value directly. Returns the instance. |
destroy() | Remove the widget and restore the original field; automatic initialization stops for that element until manually re-created. |
ready | Promise resolved when the initial country list has loaded. |
input | The original input or select element. |
wrapper | The generated visible control element. |
isOpen | Current dropdown state. |
const cs = CountrySelect.getInstance('#country');
if (cs) {
cs.setValue('CY', {silent: true});
console.log(cs.getValue(), cs.getCountry());
cs.open();
}Events:
country-change is a bubbling CustomEvent dispatched by the underlying field. Its detail contains value and country, where country is the selected country object or null. The picker also dispatches native change and input events.
document.querySelector('#country').addEventListener('country-change', event => {
console.log(event.detail.value);
console.log(event.detail.country?.phone);
});
// Native form event; compatible with htmx change triggers.
document.querySelector('#country').addEventListener('change', event => {
console.log(event.target.value);
});Web Component API:
The custom element accepts standard form attributes id, name, value, required, disabled, readonly, and accessible labels.
| Custom element attribute | JavaScript option |
|---|---|
value-type | valueType |
schema | schema |
schema-return | schemaReturn |
preferred | preferredCountries |
only-countries | onlyCountries |
exclude-countries | excludeCountries |
default-country | defaultCountry |
placeholder | placeholder |
search | search |
search-placeholder | searchPlaceholder |
no-results | noResults |
rows | rows |
dropdown-width | dropdownWidth |
popover | popover |
lang | lang |
flags | flags |
sort | sort |
countries | countries |
src | dataUrl |
base-url | baseUrl |
flag-path | flagPath |
The custom element provides the following public properties and form methods.
| Property / method | Description |
|---|---|
value | Read or set the submitted value. Assigning this property does not dispatch change events. |
country | Current country object, or null. |
instance | Underlying CountrySelect instance, or null. |
form | Associated form. |
name | Form field name. |
type | The string country-select. |
validity | Native ValidityState. |
validationMessage | Current validation message. |
willValidate | Whether the field participates in constraint validation. |
checkValidity() | Check the field’s constraints. |
reportValidity() | Check constraints and report validation errors. |
CSS Styling And Variables:
CountrySelect Pro follows Bootstrap 5 theme variables when present, including data-bs-theme="dark". On a plain CSS page, override the --cs-* variables on a parent or :root.
.shipping-form {
--cs-bg: #fff;
--cs-color: #222;
--cs-border-color: #ccc;
--cs-active-bg: #e07a2f;
--cs-active-color: #fff;
--cs-focus-border: #e07a2f;
--cs-focus-ring: rgba(224, 122, 47, 0.3);
}| CSS variable | Controls |
|---|---|
--cs-bg | Selected-field background. |
--cs-color | Text color. |
--cs-border-color | Control border. |
--cs-radius | Control corner radius. |
--cs-font-size | Control font size. |
--cs-muted | Placeholder or muted text. |
--cs-search-bg | Search field background. |
--cs-dropdown-bg | Dropdown background. |
--cs-dropdown-border-color | Dropdown border. |
--cs-divider-color | Preferred-country divider. |
--cs-active-bg | Active option background. |
--cs-active-color | Active option text. |
--cs-hover-bg | Hovered option background. |
--cs-focus-border | Focused control border. |
--cs-focus-ring | Focused control shadow color. |
--cs-invalid | Invalid control color. |
--cs-disabled-bg | Disabled field background. |
--cs-shadow | Dropdown shadow. |
--cs-shadow-up | Dropdown shadow when opened upward. |
--cs-z-index | Stacking level for in-page dropdown. |
Public CSS Classes
To supply your own styles, set window.CountrySelectConfig = {css: false} before loading the script. The following classes are used for the styled control.
| Class | Element |
|---|---|
.cs-wrapper | Outer control. |
.cs-trigger | Clickable selected-country trigger. |
.cs-selected-content | Selected value and flag. |
.cs-dropdown | Dropdown panel. |
.cs-search-input | Country search field. |
.cs-list | Country list container. |
.cs-option | List item. |
.cs-option.active | Active keyboard/navigation item. |
.cs-divider | Divider after preferred countries. |
Alternatives:
Changelog:
v6.6.0 (11/08/2026)
- Added the form-associated
<country-select>Web Component and support for instance lookup from custom elements.







