JavaScript plugin
How to get up and running with the JavaScript plugin. For the framework components instead, see React, Vue, Angular, or Svelte.
Contents
Installation
There are two ways to install the plugin: using a bundler (e.g. Vite, webpack), or using a script tag (e.g. via a CDN).
Using a bundler
First, install the package:
npm install intl-tel-input
Then, import the JS and CSS, and initialise the plugin on your input element:
import intlTelInput from "intl-tel-input";
import "intl-tel-input/styles";
const input = document.querySelector("#phone");
intlTelInput(input, {
loadUtils: () => import("intl-tel-input/utils"),
});
Note
The utils script (~260KB) is loaded separately. The example above passes a dynamic import to loadUtils — modern bundlers split this into its own lazy-loaded chunk, so it doesn’t hit your initial bundle. Alternatively, if the plugin is already lazy-loaded in your app, import from "intl-tel-input/intlTelInputWithUtils" to bundle utils directly.
Using a script tag
This example loads the assets from jsDelivr for a quick start. Alternatively, use your own hosted files.
First, add the CSS:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/intl-tel-input@27.1.3/dist/css/intlTelInput.css">
Then, add the plugin script and initialise it on your input element:
<script src="https://cdn.jsdelivr.net/npm/intl-tel-input@27.1.3/dist/js/intlTelInput.min.js"></script>
<script>
const input = document.querySelector("#phone");
window.intlTelInput(input, {
loadUtils: () => import("https://cdn.jsdelivr.net/npm/intl-tel-input@27.1.3/dist/js/utils.js"),
});
</script>
Best practices
See Best practices for general advice on loading the utils module, E.164 storage, validation, setting the initial country, strict mode, and localisation.
Initialisation options
The plugin has dozens of options for customising its behaviour — country picker, formatting, validation, placeholders, localisation, and more. See the full list on the Initialisation options page, or try them interactively in the playground.
Methods
Once the plugin is initialised, you can call methods on the returned instance — e.g. setNumber, setCountry, getNumber, isValidNumber. See the full list on the Methods page.
Events
The plugin triggers the following custom events on the <input> element. Listen for them with input.addEventListener(...).
countrychange
Triggered when the selected country is updated, e.g. if the user selects a country from the dropdown, or they type a different dial code into the input, or you call setCountry etc. The selected country data is available at e.detail (the same data returned by getSelectedCountryData).
input.addEventListener("countrychange", (e) => {
// country data
const { iso2, dialCode, name } = e.detail;
});
open:countrydropdown
Triggered when the user opens the dropdown.
close:countrydropdown
Triggered when the user closes the dropdown.
strict:reject
Fired when strictMode rejects or modifies input. For most cases, strictRejectAnimation gives you a built-in shake/flash animation without writing any code — only listen for strict:reject when you need custom feedback (e.g. a toast that explains why the input was rejected, or an aria-live announcement).
e.detail has three fields describing what was rejected and why:
source: either"key"(a keystroke) or"paste"(a clipboard paste).rejectedInput: the raw string that was rejected or stripped — for"key"this is the single character pressed, and for"paste"it’s the full pasted text.reason: either"invalid"(the input contained a disallowed character) or"max-length"(accepting the input would have exceeded the maximum valid length for the selected country).
Here is an example that selects a user-facing message based on these fields:
input.addEventListener("strict:reject", (e) => {
const { source, rejectedInput, reason } = e.detail;
let msg;
if (reason === "max-length") msg = "Maximum length reached for this country";
else if (source === "paste") msg = "Stripped invalid characters from pasted text";
else msg = `Character not allowed: "${rejectedInput}"`;
// ...show msg to the user (e.g. toast, aria-live region, inline error)
});