Vanilla JavaScript example
Precise validation (advanced)
Overview
Warning: Various countries around the world update their number rules every month, so
isValidNumberPrecise will start rejecting valid numbers unless you constantly keep it up-to-date e.g. via an automated script. For this reason, we strongly recommend sticking to the standard validation method, which is much more stable as it only checks number length rules, which rarely change.
isValidNumberPrecise respects the allowedNumberTypes option, which is set to ["MOBILE", "FIXED_LINE"] by default, meaning it will only return true for those types of numbers.
If it returns false, you can use getValidationError to get the error code, which you can then map to your own custom error message, as in the example below.
Note: the red/green styling and warning/success icons are not part of the library — in this example they come from Bootstrap form validation.
Note: the toast shown when input is rejected isn't part of the library — see the strict:reject event docs for an example of how to wire one up yourself.
Demo
Note: by default, validation only considers mobile and fixed line numbers as valid. See
allowedNumberTypes option for more information.
Html
<form id="form">
<label for="phone">Phone number</label>
<input id="phone" name="phone" type="tel">
<button type="submit">Submit</button>
</form>
<div id="error-msg"></div>
<div id="valid-msg"></div>
JavaScript
initialCountryLookup here uses ipapi's free tier. For production, swap for a paid plan or alternative - see docs.getErrorMessage is up to you - see a worked example.import intlTelInput from "intl-tel-input";
const form = document.querySelector("#form");
const input = document.querySelector("#phone");
const errorMsg = document.querySelector("#error-msg");
const validMsg = document.querySelector("#valid-msg");
const iti = intlTelInput(input, {
loadUtils: () => import("intl-tel-input/utils"),
});
// wait for utils to load before calling isValidNumber
await iti.promise;
form.addEventListener("submit", (e) => {
e.preventDefault();
if (iti.isValidNumberPrecise()) {
validMsg.textContent = `Full number: ${iti.getNumber()}`;
errorMsg.textContent = "";
} else {
const errorCode = iti.getValidationError();
// your code here to map the errorCode to a user-facing message
errorMsg.textContent = getErrorMessage(input.value, errorCode);
validMsg.textContent = "";
}
});
import intlTelInput from "intl-tel-input";
const form = document.querySelector("#form");
const input = document.querySelector("#phone");
const errorMsg = document.querySelector("#error-msg");
const validMsg = document.querySelector("#valid-msg");
const initialCountryLookup = async () => {
const res = await fetch("https://ipapi.co/json");
const data = await res.json();
return data.country_code;
};
// initialise library
const iti = intlTelInput(input, {
initialCountryLookup,
loadUtils: () => import("intl-tel-input/utils"),
});
// wait for utils to load before calling isValidNumber
await iti.promise;
let showValidation = false;
let submitted = false;
const updateUI = () => {
if (!showValidation) return;
const isValid = iti.isValidNumberPrecise();
let invalidMsg = "";
if (!isValid) {
const errorCode = iti.getValidationError();
// your code here to map the errorCode to a user-facing message
invalidMsg = getErrorMessage(input.value, errorCode);
}
errorMsg.textContent = invalidMsg;
validMsg.textContent = isValid && submitted ? `Full number: ${iti.getNumber()}` : "";
};
// on submit: validate (and show "Full number" if valid)
form.addEventListener("submit", (e) => {
e.preventDefault();
showValidation = true;
submitted = true;
updateUI();
});
// on blur: enable validation UI
input.addEventListener("blur", () => {
showValidation = true;
updateUI();
});
// while typing / pasting / changing country: remove any submitted state and update validity state
input.addEventListener("input", () => {
submitted = false;
updateUI();
});