Phone input
A phone input takes an international phone number: a country code picker joined to a number field that formats as you type. It is a bare box; wrap it in a
<tk-field label="Phone number" required> <tk-phone-input name="phone" country="US"></tk-phone-input> </tk-field>
Anatomy
| Part | What it is |
|---|---|
tk-phone-input |
the element; two Tab stops, the prefix and the number |
field part |
the bordered box around both segments |
prefix part |
a compact |
number part |
the native <input type="tel"> for the national number |
The label, help text, and error message come from a country-label.
Sizes
<tk-phone-input aria-label="Medium phone input" country="GB"></tk-phone-input> <tk-phone-input aria-label="Large phone input" country="GB" size="large"></tk-phone-input>
size |
Height |
|---|---|
medium (default) |
32px |
large |
36px |
The phone input fills its container's width.
States
<tk-phone-input aria-label="Office phone" value="+12133734253" readonly></tk-phone-input> <tk-phone-input aria-label="Office phone" value="+12133734253" disabled></tk-phone-input>
<tk-field label="Phone number" error="Enter a phone number, like 07700 900 982"> <tk-phone-input name="phone" country="GB" value="+44770"></tk-phone-input> </tk-field>
The box doesn't change on hover. Focus on either segment lights the one shared border, which grows thicker inward.
readonly: people can read and copy the number, but not edit it.disabled: both segments can't be focused or edited, and nothing is submitted.- Error: set
erroron the Field. The border turns red and stays red while focused. - Required: set
requiredon the Field; it adds the asterisk and makes the number required.
Formatting and value
- The number formats as you type, grouped the way each country writes it. To keep raw
digits, set the
formatproperty tofalsein code; the attribute can't turn it off. - Typing a
+code switches the country. The field never adds a code you didn't type. - The placeholder is an example number for the selected country, unless you set
placeholder. valueis the full number in E.164 format, such as+12133734253. It's what the form submits undernameand what you should store. Settingvaluefills both segments.countryis the selected country's two-letter code;nationalNumberis the number without the country code. Detecting a country from location or language is up to you.
Validation
The phone input doesn't check the number unless you ask. Then you decide when to show an error on the Field.
validate: an invalid number blocks the form from submitting. It doesn't turn the box red or show a message.checkPhoneValidity(): returns{ valid, reason }. Call it on blur or submit, and turn the result into the Field'serror.
Use validation to tell people what's wrong, never to rewrite what they typed.
Label, help text, and errors
<tk-phone-input aria-label="Mobile number" country="DE"></tk-phone-input>
- Wrap the phone input in a
Field . The Field's label, help text, and error name and describe the number field. - Without a visible label, set
aria-label(oraria-labelledby) on the phone input. - A placeholder is never a label: it disappears as soon as people type.
When to use
- Use a phone input when people may enter numbers from different countries, such as at signup or checkout.
- Use an
Input withtype="tel"for a single country, or when a picker adds more effort than it saves. Let people type the whole number, with any country code. - Use an
OTP input for a verification code. - Use a
Country select to pick a country without a phone number.
<tk-field label="Phone number" helper="Include the country code for numbers outside the UK, like +33"> <tk-input type="tel" name="phone" autocomplete="tel"></tk-input> </tk-field>
Content
- Label it "Phone number" or what the number is for: "Mobile number", "Work phone".
- Say what to do in an error: "Enter a phone number, like 07700 900 982". No "invalid".
- Explain why you need the number in the help text, if it isn't obvious.
More in
Do / Don't
| ✅ Do | ❌ Don't |
|---|---|
Wrap it in a Field, or set aria-label |
Expect the phone input to show a label |
Store and submit the E.164 value |
Store the formatted display text |
Set country, or let the user pick it |
Assume a country the user didn't choose |
Use a plain tel input for a single country |
Add a picker that only adds effort |
| Validate on blur or submit, to inform | Recolor or rewrite the number as people type |
| Use an OTP input for verification codes | Use a phone input for a code |
Related
Field : the label, help text, and error.Country select : the country picker on its own.Input : a plaintelfield, for a single country.OTP input : the verification code that often follows.
API
Attributes
| Attribute | Type | Default | What it does |
|---|---|---|---|
value |
string | '' |
the number in E.164 format; setting it fills both segments |
country |
string | the selected country, a two-letter code such as US |
|
name |
string | the form field name; submits the E.164 value | |
format |
boolean | true |
formats the number as you type; set the property to false to stop |
validate |
boolean | false |
an invalid number blocks submit; nothing visible changes |
placeholder |
string | replaces the example number | |
country-label |
string | Country calling code |
the prefix's accessible name |
size |
medium | large |
medium |
height 32 or 36px |
required |
boolean | false |
the number is required; inside a Field, set it on the Field |
disabled |
boolean | false |
not focusable, not editable, left out of the form |
readonly |
boolean | false |
focusable and copyable, not editable |
locale |
string | the language of the country names in the list | |
inputmode |
string | tel |
the number field's keyboard |
autocomplete |
string | tel-national |
the number field's autofill hint |
Properties
| Property | Type | What it does |
|---|---|---|
nationalNumber |
string, read-only | the number without the country code |
Events
input fires on every edit and on a country pick. change fires when an edit is committed
on blur, and on a country pick. Read value, country, or nationalNumber. change doesn't
cross shadow roots; listen on the element. Resetting the form restores the first value.
Methods
focus(): moves focus to the number field.checkPhoneValidity(): resolves to{ valid, reason }.
CSS
::part(field): the bordered box.::part(prefix): the country code picker.::part(number): the native number<input>.
Tokens
| Role | Rest | Focus | Error | Disabled | Read-only |
|---|---|---|---|---|---|
| border | border/subtle |
border/accent/focus |
border/error |
border/disabled |
border/subtle |
| background | surface/default |
surface/default |
surface/default |
surface/disabled |
surface/subtle |
The line between the segments is border/subtle. The placeholder is text/placeholder.
Corners are radius-8. The phone input uses the same tokens as
Accessibility
Built in:
- Two named parts: the Field names the number field, and the prefix is a combobox named "Country calling code".
- The number field uses the phone keypad and
autocomplete="tel-national"; the prefix usesautocomplete="tel-country-code". - A composing Field links the help text and error to the number field and marks it invalid.
- The focus border is never hidden.
Your part:
- Give the phone input a name: a Field label, or
aria-label. - Consider whether the picker helps. For a single country, a plain
telinput is often easier for everyone.
| Key | Action |
|---|---|
Tab |
moves from the prefix to the number field |
| typing, in the prefix | filters the country list; the dial code is selected on focus, so the first key starts a search |
↓ / ↑, Enter, Esc, in the prefix |
as in |
Contrast limits
- Resting border: 1.33:1 in light and 2.00:1 in dark, under the 3:1 minimum; 4.22:1 in high contrast. Give every phone input a visible label so the border isn't the only cue.