Vanilla JavaScript example

Hidden input

Overview

If you're using traditional form submissions (rather than fetch), the input values need to contain everything you want sent before submit. That's a problem if the user enters their number in national format or with separateDialCode enabled, as the input value won't include the full international number.

The hiddenInputs option solves this by listening for the form submit event and injecting a hidden input with the full international number (and another with the selected country iso2 code, e.g. "gb"), which get submitted along with the rest of your form data.

In the demo below, we use hiddenInputs to define a full_phone input. Enter a valid number and click submit to see it in action. The form posts to the current URL, so the page reloads with the submitted input values in the URL query string. You will see phone contains the typed number (without the dial code), and full_phone contains the full international number.

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

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, {
  hiddenInputs: () => ({
    phone: "full_phone",
    country: "country_iso2",
  }),
  loadUtils: () => import("intl-tel-input/utils"),
});

// wait for utils to load before calling isValidNumber
await iti.promise;

// validate on submit, prevent submission if invalid
form.addEventListener("submit", (e) => {
  if (iti.isValidNumber()) {
    errorMsg.textContent = "";
  } else {
    e.preventDefault();
    const errorCode = iti.getValidationError();
    // your code here to map the errorCode to a user-facing message
    errorMsg.textContent = getErrorMessage(input.value, errorCode);
  }
});

// if the form was submitted and the page reloaded with the full phone number in the query string, show it here
const urlParams = new URLSearchParams(window.location.search);
const phone = urlParams.get("phone");
const fullPhone = urlParams.get("full_phone");
if (fullPhone) {
  validMsg.innerHTML = `Submitted values<br>phone: ${phone}<br>full_phone: ${fullPhone}`;
}
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, {
  hiddenInputs: () => ({
    phone: "full_phone",
    country: "country_iso2",
  }),
  initialCountryLookup,
  loadUtils: () => import("intl-tel-input/utils"),
});

// wait for utils to load before calling isValidNumber
await iti.promise;

// validation code
let showValidation = false;

const updateUI = () => {
  if (!showValidation) return;

  let invalidMsg = "";
  const isValid = iti.isValidNumber();
  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;
  return isValid;
};

// on submit: enable validation UI
form.addEventListener("submit", (e) => {
  showValidation = true;
  const isValid = updateUI();
  if (!isValid) {
    e.preventDefault();
  }
});

// on blur: enable validation UI
input.addEventListener("blur", () => {
  showValidation = true;
  updateUI();
});

// while typing / pasting / changing country: update validity state
input.addEventListener("input", updateUI);

// if the form was submitted and the page reloaded with the full phone number in the query string, show it here
const urlParams = new URLSearchParams(window.location.search);
const phone = urlParams.get("phone");
const fullPhone = urlParams.get("full_phone");
if (fullPhone) {
  validMsg.innerHTML = `Submitted values<br>phone: ${phone}<br>full_phone: ${fullPhone}`;
}