On this page
Phone numbers look simple until you collect them from real people. One person types 07700 900123, another +44 7700 900123, another (555) 010-4477, and another adds an extension. Validation that's too strict rejects real customers; validation that's too loose fills your CRM with junk.
Here's a practical approach.
Step 1: Use type="tel"
<label for="phone">Phone number</label>
<input id="phone" name="phone" type="tel" autocomplete="tel">
- Phones show a numeric keypad with
+,*and#. autocomplete="tel"lets browsers fill in the person's number.- Unlike
type="email",type="tel"doesn't validate any format — on purpose, because formats vary so much worldwide.
Never use type="number" for phone numbers. It drops leading zeros, may show spinner arrows, and rejects +, spaces and dashes.
Step 2: Decide what you actually need
Before writing a pattern, ask:
- Do you serve one country or many? A single-country form can be stricter.
- Will you call or text the number? If you'll send SMS, you need it in full international format.
- Is it required? If you only call occasionally, making it optional increases completions.
Step 3: A flexible pattern for international numbers
This accepts an optional +, then digits with common separators, and requires a sensible length:
<input id="phone" name="phone" type="tel" autocomplete="tel"
pattern="^\+?[0-9\s\-\(\)\.]{7,20}$"
title="Enter a phone number, e.g. +44 7700 900123">
It allows +1 (555) 010-4477, 07700 900123 and +91 98765 43210, and rejects letters and obviously short entries. It won't catch every invalid number — no simple pattern can.
Step 4: Single-country patterns
If you only accept one country, you can be precise. Strip separators first and validate the digits. For example, a US number (10 digits, optional +1):
<input id="phone" name="phone" type="tel" autocomplete="tel"
pattern="^(\+?1[\s\-.]?)?\(?[2-9][0-9]{2}\)?[\s\-.]?[0-9]{3}[\s\-.]?[0-9]{4}$"
title="Enter a 10-digit US phone number">
Even then, consider an "I'm outside the US" option — customers travel and move.
Step 5: Ask for the country separately
For international forms, a country selector next to the number makes formatting unambiguous and lets you show the right example:
<div class="phone-row">
<label for="cc" class="sr-only">Country code</label>
<select id="cc" name="phone_country" autocomplete="tel-country-code">
<option value="+1">🇺🇸 +1</option>
<option value="+44">🇬🇧 +44</option>
<option value="+91" selected>🇮🇳 +91</option>
<option value="+61">🇦🇺 +61</option>
</select>
<label for="phone" class="sr-only">Phone number</label>
<input id="phone" name="phone" type="tel" autocomplete="tel-national"
inputmode="tel" placeholder="98765 43210">
</div>
autocomplete="tel-country-code" and tel-national tell the browser to fill the two parts separately.
Step 6: Normalise to E.164 before storing
E.164 is the international standard format: a +, the country code, then the number with no spaces — for example +447700900123. Storing numbers this way makes them work with SMS providers, CRMs and click-to-call.
function toE164(countryCode, national) {
const digits = national.replace(/\D/g, '').replace(/^0+/, ''); // drop separators and trunk zero
return countryCode + digits;
}
toE164('+44', '07700 900123'); // "+447700900123"
The "drop the leading zero" rule works for many countries but not all (Italy, for example, keeps it). For real-world accuracy across countries, use a dedicated library such as libphonenumber (available as libphonenumber-js for JavaScript), which knows the rules for every country — validity, length, mobile vs landline and formatting.
import { parsePhoneNumberFromString } from 'libphonenumber-js';
const phone = parsePhoneNumberFromString('07700 900123', 'GB');
phone.isValid(); // true
phone.number; // "+447700900123"
Step 7: Validate on the server
Run the same check where the data is received. Browser validation can be bypassed, and server-side libraries are just as easy to use. If the number is critical (two-factor login, delivery updates), verify it by sending a one-time code by SMS.
UX tips
- Show an example in the placeholder or hint text.
- Accept any separators and clean them up yourself — don't force people to remove spaces.
- Don't split the number into three boxes — it breaks paste and autofill.
- Explain why you need it: "So the driver can reach you on delivery day."
- Make it optional unless you truly need it.
Putting it together
<form action="https://api.formclick.io/submit" method="POST">
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY">
<label for="phone">Phone (optional)</label>
<input id="phone" name="phone" type="tel" autocomplete="tel"
pattern="^\+?[0-9\s\-\(\)\.]{7,20}$"
title="Enter a phone number, e.g. +44 7700 900123"
aria-describedby="phone-hint">
<p id="phone-hint" class="hint">Include your country code if you're outside the UK.</p>
<button type="submit">Request a callback</button>
</form>
Submissions posted to Formclick arrive with the number exactly as typed, so you can normalise it in your CRM or with a webhook workflow. Need a ready-made layout? Try the callback request template.



