PhoneInput
Country-code Select plus a national-number Input. Emits an E.164 string
(+CC<NSN>). Used for booking-phone verification and any consumer signup.
Default#
Loading…
With existing value#
The component parses incoming E.164 values back into country + national number, so it round-trips cleanly with server state.
Loading…
Props#
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | undefined | — | E.164 value (controlled), e.g. `+14155550100`. |
| defaultValue | string | undefined | — | Default E.164 value (uncontrolled). |
| onValueChange | ((value: string) => void) | undefined | — | Fires with the new E.164 value. Empty national number → empty string. |
| countries | readonly PhoneCountry[] | undefined | [
{ code: 'US', name: 'United States', dialCode: '1', flag: '🇺🇸' },
{ code: 'CA', name: 'Canada', dialCode: '1', flag: '🇨🇦' },
{ code: 'MX', name: 'Mexico', dialCode: '52', flag: '🇲🇽' },
{ code: 'GB', name: 'United Kingdom', dialCode: '44', flag: '🇬🇧' },
{ code: 'IE', name: 'Ireland', dialCode: '353', flag: '🇮🇪' },
{ code: 'DE', name: 'Germany', dialCode: '49', flag: '🇩🇪' },
{ code: 'FR', name: 'France', dialCode: '33', flag: '🇫🇷' },
{ code: 'ES', name: 'Spain', dialCode: '34', flag: '🇪🇸' },
{ code: 'IT', name: 'Italy', dialCode: '39', flag: '🇮🇹' },
{ code: 'PT', name: 'Portugal', dialCode: '351', flag: '🇵🇹' },
{ code: 'NL', name: 'Netherlands', dialCode: '31', flag: '🇳🇱' },
{ code: 'BE', name: 'Belgium', dialCode: '32', flag: '🇧🇪' },
{ code: 'CH', name: 'Switzerland', dialCode: '41', flag: '🇨🇭' },
{ code: 'AT', name: 'Austria', dialCode: '43', flag: '🇦🇹' },
{ code: 'SE', name: 'Sweden', dialCode: '46', flag: '🇸🇪' },
{ code: 'NO', name: 'Norway', dialCode: '47', flag: '🇳🇴' },
{ code: 'DK', name: 'Denmark', dialCode: '45', flag: '🇩🇰' },
{ code: 'FI', name: 'Finland', dialCode: '358', flag: '🇫🇮' },
{ code: 'PL', name: 'Poland', dialCode: '48', flag: '🇵🇱' },
{ code: 'CZ', name: 'Czechia', dialCode: '420', flag: '🇨🇿' },
{ code: 'GR', name: 'Greece', dialCode: '30', flag: '🇬🇷' },
{ code: 'TR', name: 'Turkey', dialCode: '90', flag: '🇹🇷' },
{ code: 'IL', name: 'Israel', dialCode: '972', flag: '🇮🇱' },
{ code: 'AE', name: 'UAE', dialCode: '971', flag: '🇦🇪' },
{ code: 'SA', name: 'Saudi Arabia', dialCode: '966', flag: '🇸🇦' },
{ code: 'IN', name: 'India', dialCode: '91', flag: '🇮🇳' },
{ code: 'CN', name: 'China', dialCode: '86', flag: '🇨🇳' },
{ code: 'JP', name: 'Japan', dialCode: '81', flag: '🇯🇵' },
{ code: 'KR', name: 'South Korea', dialCode: '82', flag: '🇰🇷' },
{ code: 'SG', name: 'Singapore', dialCode: '65', flag: '🇸🇬' },
{ code: 'AU', name: 'Australia', dialCode: '61', flag: '🇦🇺' },
{ code: 'NZ', name: 'New Zealand', dialCode: '64', flag: '🇳🇿' },
{ code: 'BR', name: 'Brazil', dialCode: '55', flag: '🇧🇷' },
{ code: 'AR', name: 'Argentina', dialCode: '54', flag: '🇦🇷' },
{ code: 'CL', name: 'Chile', dialCode: '56', flag: '🇨🇱' },
{ code: 'CO', name: 'Colombia', dialCode: '57', flag: '🇨🇴' },
{ code: 'ZA', name: 'South Africa', dialCode: '27', flag: '🇿🇦' },
] | Custom country list. Defaults to the bundled subset. |
| defaultCountry | string | undefined | US | Default selected country code. Default `'US'`. |
| placeholder | string | undefined | Phone number | |
| disabled | boolean | undefined | — | |
| id | string | undefined | — | `id` for the national-number `<input>` so an external `<label htmlFor>` (or a `Field` render-prop's generated id) can target it. |
| aria-label | string | undefined | Phone number | Accessible label for the national-number input. |
| aria-describedby | string | undefined | — | Forwarded to the national-number input — e.g. a `Field`'s describedby id. |
| aria-invalid | boolean | undefined | — | Forwarded to the national-number input — e.g. a `Field`'s invalid flag. |
Country list#
The component ships with a curated subset of common origins (~35 countries).
For a production deployment in many markets, pass a countries prop sourced
from libphonenumber-js or world-countries:
tsx
import { getCountries, getCountryCallingCode } from 'libphonenumber-js';
const countries = getCountries().map((code) => ({
code,
name: code,
dialCode: getCountryCallingCode(code),
flag: codeToFlag(code),
}));
<PhoneInput countries={countries} />;Accessibility#
- Country select has
aria-label="Country"; national input has its ownaria-label(override viaaria-labelprop). type="tel"+inputMode="tel"give mobile keyboards the dial pad.autoComplete="tel-national"works with iOS / Android contact autofill.