intl-tel-input Phone Field with Validation — Free JS Snippet

intl-tel-input International Phone Field with Validation · Forms · Plain HTML, CSS & JS · Live preview

CategoryForms

What's included

Features

Searchable country dropdown with flags and preferred countries pinned to the top
Separate dial code so users only type the national number
Real validation using libphonenumber metadata via utils.js
Specific error messages from getValidationError()
E.164 output from getNumber() ready for APIs and databases
Number type detection (mobile, landline, toll-free, VoIP)
Aggressive placeholders showing an example for the chosen country
Graceful fallback when the lazy utils script cannot load

About this UI Snippet

intl-tel-input International Phone Field — HTML, CSS & JavaScript

Screenshot of the intl-tel-input International Phone Field with Validation snippet rendered live

Where a formatting mask makes a phone number look right, intl-tel-input makes it be right. It adds a searchable country dropdown with flags, keeps the dial code separate from the national number, and — the important part — validates against real numbering-plan metadata, the same data behind Google's libphonenumber. A number is not just "long enough": it has to be possible and valid for the selected country, and this field can tell the difference.

The heavy lifting lives in a second file. The main script is small; validation, formatting and per-country example placeholders come from utils.js, which is loaded lazily via the utilsScript option. Until it has loaded, isValidNumber() cannot give a meaningful answer, which is a classic source of "valid numbers rejected" bugs on slow connections. This snippet waits for iti.promise, shows a loading message in the meantime, and falls back gracefully if the script cannot be fetched — the field still works as a country picker even without validation.

The output that matters is E.164, returned by getNumber(): a plus sign, the country code and the national digits with no spaces or punctuation, such as +16502530000. That is the canonical form SMS providers, identity checks and databases expect, so it is the value to send. The field also reports the number type — mobile, landline, toll-free and so on — using the utility library, which is useful for deciding whether an SMS verification is even possible.

Error handling uses getValidationError() codes rather than a generic "invalid" message, so the user hears "Too short" or "Wrong length for this country" and can fix the problem. autoPlaceholder: 'aggressive' shows a real example number for the chosen country, which prevents many mistakes before they happen. separateDialCode keeps the +44 in the flag button, so users type only their national number and never wonder whether to include the leading zero.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Ask an AI assistant like Claude to add a server-side validation example with libphonenumber-js, restrict the field to mobile numbers only, or send a verification code after a valid number is entered.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build an international phone field with intl-tel-input 18 loaded from a CDN, including its CSS.

Requirements:
- Initialise with initialCountry, preferredCountries, separateDialCode: true, nationalMode: true, autoPlaceholder: 'aggressive' and a utilsScript URL for lazy validation.
- Wait for iti.promise before validating; show a loading state and a graceful message if utils.js fails to load.
- On input and countrychange, use isValidNumber(); when invalid show a specific message from getValidationError(), when valid show getNumber() as E.164.
- Show the detected country and, when valid, the number type (mobile, landline, etc.).
- Add buttons that call setNumber() with sample numbers, including a deliberately too-short one.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

<div class="it-card">
  <label class="it-label" for="itPhone">Mobile number</label>
  <input id="itPhone" type="tel" autocomplete="tel">
  <p class="it-status" id="itStatus" role="status" aria-live="polite">Loading validation data...</p>
  <dl class="it-read">
    <div><dt>E.164 (send this)</dt><dd id="itE164">-</dd></div>
    <div><dt>Country</dt><dd id="itCountry">-</dd></div>
    <div><dt>Type</dt><dd id="itType">-</dd></div>
  </dl>
  <div class="it-try">Try:
    <button type="button" data-n="+1 650 253 0000">US</button>
    <button type="button" data-n="+44 7911 123456">UK</button>
    <button type="button" data-n="+91 98765 43210">India</button>
    <button type="button" data-n="+49 1512 3456789">Germany</button>
    <button type="button" data-n="+1 555">Too short</button>
  </div>
</div>

Step by step

How to Use

  1. 1
    Pick a countryClick the flag to open the searchable list. The dial code and placeholder example update.
  2. 2
    Type a numberType a national number. The border and message show whether it is valid for that country.
  3. 3
    Read the E.164 valueA valid number produces a compact +country-digits string — the value to send to your server.
  4. 4
    Try the shortcutsUse the buttons to load a US, UK, Indian or German number, or a deliberately too-short one.
  5. 5
    Change the countrySwitch country with digits still typed and the number is re-validated against the new plan.

Real-world uses

Common Use Cases

Signup and 2FA flows
Collect a number you can actually text. For a lighter, formatting-only alternative see the Cleave.js phone input.
SHOP
International checkout
Capture delivery contact numbers for customers in any country with fewer failed deliveries.
ADMIN
CRM and lead forms
Store clean E.164 numbers so calling and messaging integrations just work.
Learning lazy-loaded dependencies
A practical case of waiting for an async utility before trusting validation results.

Got questions?

Frequently Asked Questions

E.164 is the international phone format: a plus sign, country code and digits with no spaces, up to 15 digits. It is unambiguous, so SMS and calling APIs expect it.

The metadata for each country's numbering plan lives in utils.js. Without it the field can pick countries but cannot say whether a number is valid.

Use the instance's promise property, iti.promise, which resolves once the script is ready or rejects if it fails.

No. Treat it as a usability aid and re-validate the E.164 number on the server before sending messages.

Use a geoIpLookup callback with initialCountry: "auto", or read the browser locale, and pin common countries with preferredCountries.

Yes. Use onlyCountries to allow a fixed list, or excludeCountries to remove specific ones.

Yes. Use the JSX, Vue, Angular or Tailwind export buttons on this page to convert the markup and styles. The behaviour comes from intl-tel-input, so in a framework project install it with npm install intl-tel-input (official React, Vue and Angular wrappers exist) instead of the CDN tag, create it in useEffect / onMounted / ngAfterViewInit and load utils.js, and release it with destroy() when the component unmounts.