On this page
- What does input type tel actually do?
- Why input type tel does not validate phone numbers
- How to validate an HTML input phone number
- Input type tel vs inputmode: which keyboard appears?
- Which autocomplete value fits a phone field?
- Why phone numbers need a server-side check
- How SendForm checks phone numbers on hosted forms
- Frequently asked questions
What does input type tel actually do?
An <input type="tel"> is a single-line text field. Two things are worth knowing:
- A phone keypad on touch devices. iOS and Android show a dial pad with digits and, depending on the platform, the
+,*and#keys, instead of the full letter keyboard. - No autofill on its own. The type only changes the keyboard. Autofill comes from
autocomplete="tel", so add that attribute next to the type.
On a desktop with a physical keyboard, it looks and works exactly like type="text". Here is the smallest useful version:
<label for="phone">Phone number</label>
<input type="tel" id="phone" name="phone" autocomplete="tel">Why input type tel does not validate phone numbers
The email and URL input types check their values' syntax. The tel type does not. The MDN reference for input type tel explains why: phone number formats vary too much around the world for one built-in rule to work. The only thing the browser cleans up is line breaks. Everything else goes through as typed.
So call me maybe is a perfectly valid value for a tel field. The :invalid pseudo-class never fires on format alone, and the form submits without a complaint.
Easy to miss: a tel field without a pattern only triggers built-in errors for required and minlength. maxlength shows no error for typed input. It only caps what can be typed. If the field passes those, the browser sends whatever the user typed.
How to validate an HTML input phone number
The browser gives you three tools for a phone field: pattern, minlength and maxlength. The first two show a built-in error. maxlength only caps what can be typed. None of them knows real phone number rules. They just keep obvious junk out and give quick feedback before the form reaches your server.
Adding a pattern to the html tel input
A loose pattern that lets real formats through works better than a strict one that locks out foreign numbers. This one allows an optional leading plus, then 7 to 15 digits, with spaces, hyphens, dots and parentheses allowed around them. A value made only of spaces fails, because the digits are required:
<input type="tel" id="phone" name="phone"
autocomplete="tel"
pattern="\+?[ \-.\(\)]*(?:[0-9][ \-.\(\)]*){7,15}"
maxlength="32"
placeholder="+44 20 7946 0000"
aria-describedby="phone-hint">
<p id="phone-hint">Include your country code, for example +44.</p>The pattern must match the whole value, and the browser only checks it when the field is not empty. Current browsers compile the pattern with the regex v flag, so characters like (, ) and - inside a character class need a backslash, as in the pattern above. For more on how the regex behaves, see our guide to the input pattern attribute.
Tell people the format. A pattern error only says the format doesn't match. Show a hint under the field, or add a title, so people know what to fix.
Input type tel vs inputmode: which keyboard appears?
The inputmode attribute only picks the on-screen keyboard. It does not change the type, the value or any validation. That makes it useful when the data isn't really a phone number but the keypad fits.
| Markup | Touch keyboard | Built-in format check | Good for |
|---|---|---|---|
type="text" | Full letter keyboard | None | Free text |
type="tel" | Phone keypad | None | Phone numbers |
type="text" inputmode="tel" | Phone keypad | None | Same as tel, when you can't change the type |
type="text" inputmode="numeric" | Digits only | None | PINs, one-time codes, card numbers |
type="number" | Numeric, varies by platform | Rejects anything that is not a number | Quantities you calculate with |
MDN's page on the inputmode global attribute lists every value: none, text, decimal, numeric, tel, search, email and url.
inputmode="decimal" shows digits plus a decimal separator. It is for amounts such as prices, not phone numbers.
On iOS, the tel pad includes the +, * and # keys, while the numeric pad shows digits only.
When to use inputmode numeric instead
Use inputmode="numeric" for strings of digits that aren't phone numbers, like verification codes or postal codes in countries that use only digits. It usually hides the + key, which is why it's a poor fit for international phone numbers.
Why not use type number for phone numbers?
type="number" treats the value as a quantity. A value with + or spaces, like +1 555 0100, doesn't count as a number, so the field reports it as invalid. Desktop browsers may also add spinner arrows and let the scroll wheel change the value. A phone number isn't something you add or subtract, so keep it in a tel field.
Which autocomplete value fits a phone field?
Autofill saves people the most typing on phone fields. For a single field, autocomplete="tel" asks for the full number, including the country code. If your form splits the number into separate fields, the spec also defines tel-country-code, tel-national, tel-area-code, tel-local and tel-extension.
<label for="country-code">Country code</label>
<select id="country-code" name="country_code" autocomplete="tel-country-code">...</select>
<label for="phone-national">Phone number</label>
<input type="tel" id="phone-national" name="phone_national" autocomplete="tel-national">A single field with tel is usually easier for people to fill in. Our autocomplete attribute guide covers the other tokens and when to turn autofill off.
Why phone numbers need a server-side check
Anyone can edit the form in DevTools or post straight to your endpoint, skipping every client-side rule. The server is where phone numbers should get their real check:
- Strip formatting such as spaces, dots, hyphens and parentheses before you store or compare numbers.
- Check the length and allowed characters again, even if the browser already did.
- Normalize to E.164 (for example
+442079460000) if you send texts or match numbers. Google's libphonenumber and its ports parse, validate and format numbers for each country.
Don't reject numbers that look odd but are real. Extensions, short national numbers and people typing with a leading zero are all common. Wrongly rejecting a real customer costs you more than accepting a few messy numbers.
How SendForm checks phone numbers on hosted forms
In SendForm's hosted form builder, a Phone question is a tel field as well. The public form renders it as type="tel" with autocomplete="tel" and a maxlength of 32 characters.
The answer is checked twice with a loose rule of its own: 5 to 32 characters, made up of digits, spaces, +, parentheses, hyphens and dots. The browser checks it first and shows Enter a valid phone number. under the field. The server checks it again on submit, so a request that skips the page still gets rejected.
Using SendForm with your own HTML form instead? Then the markup is up to you, and so is the checking. SendForm stores a tel field from your own form exactly as typed and does not check it. With no backend of your own, use the pattern in the browser and clean the number wherever you use it, for example in the service that receives your webhook.
Ready to collect phone numbers from a static site?
- Keep your own HTML form and its tel field
- Point the form at a SendForm endpoint, no backend code needed
- Get submissions by email and webhook, with spam protection built in
Frequently asked questions
No. The browser accepts any text in a tel field and only removes line breaks. Format checks only happen if you add a pattern yourself. Minlength adds a length error, and maxlength only caps what can be typed. Even then, check the number again on the server, because client-side rules are easy to get around.
Use type tel. A phone number isn't a quantity. A number field reports values with a plus sign or spaces as invalid, and on desktop it may show spinner arrows or change the value when someone scrolls. Type tel keeps the text exactly as typed and still shows a phone keypad on touch devices.
Inputmode tel shows a phone keypad, which usually includes the plus, star and hash keys. Inputmode numeric shows a plain digit pad and is better for codes and PINs. Neither one validates anything. They only change the on-screen keyboard on touch devices.
Keep it loose. Something like an optional plus followed by 7 to 15 digits, with spaces, hyphens, dots and parentheses allowed between them, works for most countries. Strict per-country patterns end up rejecting real numbers. For accurate checks, parse the number on the server with a library such as libphonenumber and store it in E.164 format.
The field is probably type text with no inputmode. Change it to type tel, or add inputmode tel if a script or framework controls the type. Also make sure the page isn't loading a custom keyboard or input library that overrides the attribute after the page loads.


