PhoneInput
PhoneInput component provides a flexible way to capture telephone numbers with built-in masking and formatting.Examples
(7)Properties
(63)Playground
Basic
Loading demo…
import
{
useState
}
from
'react'
;
import
{
Block
,
Card
,
Code
,
PhoneInput
,
Text
}
from
'@platform-blocks/react-ui-library'
;
export
function
Demo
(
)
{
const
[
raw
,
setRaw
]
=
useState
(
''
)
;
const
[
formatted
,
setFormatted
]
=
useState
(
''
)
;
const
[
e164
,
setE164
]
=
useState
(
''
)
;
const
[
complete
,
setComplete
]
=
useState
(
false
)
;
return
(
<Block
fullWidth
>
<Text
weight
=
"semibold"
>
Basic
phone input
</Text
>
<Text
size
=
"sm"
color
=
"secondary"
>
Controlled
phone field showing the raw national digits
,
the formatted display
value
,
and the submittable
E
.
164
form
.
</Text
>
<PhoneInput
label
=
"Phone number"
value
=
{
raw
}
onChange
=
{
(
rawDigits
,
formattedDisplay
,
meta
)
=>
{
setRaw
(
rawDigits
)
;
setFormatted
(
formattedDisplay
)
;
setE164
(
meta
.
e164
)
;
setComplete
(
meta
.
isComplete
)
;
}
}
country
=
"US"
showCountryCode
/>
<Card
variant
=
"outline"
p
=
"sm"
>
<Block
>
<Text
size
=
"xs"
color
=
"secondary"
>
Current
values
</Text
>
<Code
size
=
"sm"
>
{
JSON
.
stringify
(
{
raw
,
formatted
,
e164
,
complete
}
,
null
,
2
)
}
</Code
>
</Block
>
</Card
>
</Block
>
)
;
}
International
Loading demo…
import
{
useState
}
from
'react'
;
import
{
Block
,
Card
,
Code
,
PhoneInput
,
Text
}
from
'@platform-blocks/react-ui-library'
;
export
function
Demo
(
)
{
const
[
autoDetectValue
,
setAutoDetectValue
]
=
useState
(
''
)
;
const
[
autoDetectE164
,
setAutoDetectE164
]
=
useState
(
''
)
;
const
[
autoDetectCountry
,
setAutoDetectCountry
]
=
useState
(
'US'
)
;
const
[
intlValue
,
setIntlValue
]
=
useState
(
''
)
;
const
[
intlFormatted
,
setIntlFormatted
]
=
useState
(
''
)
;
return
(
<Block
fullWidth
>
<Text
weight
=
"semibold"
>
International
detection
</Text
>
<Text
size
=
"sm"
color
=
"secondary"
>
With
autoDetect
,
an explicit
+
prefix picks the country
:
type
or paste
+
447911123456
and the mask
,
dial code and
E
.
164
output follow along
.
A
recognized dial code is stripped on paste either way
,
so a full international
number
never
overflows the national mask
.
</Text
>
<Block
>
<PhoneInput
label
=
"Auto-detect from a + prefix"
value
=
{
autoDetectValue
}
onChange
=
{
(
raw
,
_formatted
,
meta
)
=>
{
setAutoDetectValue
(
raw
)
;
setAutoDetectE164
(
meta
.
e164
)
;
}
}
defaultCountry
=
"US"
onCountryChange
=
{
setAutoDetectCountry
}
autoDetect
showCountryCode
placeholder
=
"Try +447911123456 or +33123456789"
/>
<PhoneInput
label
=
"Manual international"
country
=
"INTL"
value
=
{
intlValue
}
onChange
=
{
(
raw
,
formatted
)
=>
{
setIntlValue
(
raw
)
;
setIntlFormatted
(
formatted
)
;
}
}
showCountryCode
=
{
false
}
placeholder
=
"Enter any international number"
/>
</Block
>
<Card
variant
=
"outline"
p
=
"sm"
>
<Block
>
<Text
size
=
"xs"
color
=
"secondary"
>
Values
</Text
>
<Code
size
=
"sm"
>
{
JSON
.
stringify
(
{
autoDetect
:
{
country
:
autoDetectCountry
,
raw
:
autoDetectValue
,
e164
:
autoDetectE164
}
,
international
:
{
raw
:
intlValue
,
formatted
:
intlFormatted
}
}
,
null
,
2
)
}
</Code
>
</Block
>
</Card
>
</Block
>
)
;
}
Country Picker
Loading demo…
import
{
useState
}
from
'react'
;
import
{
Block
,
Card
,
Code
,
PhoneInput
,
Text
}
from
'@platform-blocks/react-ui-library'
;
export
function
Demo
(
)
{
const
[
country
,
setCountry
]
=
useState
(
'US'
)
;
const
[
raw
,
setRaw
]
=
useState
(
''
)
;
const
[
e164
,
setE164
]
=
useState
(
''
)
;
return
(
<Block
fullWidth
>
<Text
weight
=
"semibold"
>
Country
picker
</Text
>
<Text
size
=
"sm"
color
=
"secondary"
>
With
selectableCountry the dial
-
code prefix becomes a dropdown
.
Changing
the
country remasks the digits already entered instead of clearing them
,
and the
E
.
164
value is rebuilt against the
new
dial code
.
</Text
>
<PhoneInput
label
=
"Phone number"
selectableCountry
country
=
{
country
}
onCountryChange
=
{
setCountry
}
value
=
{
raw
}
onChange
=
{
(
rawDigits
,
_formatted
,
meta
)
=>
{
setRaw
(
rawDigits
)
;
setE164
(
meta
.
e164
)
;
}
}
/>
<Card
variant
=
"outline"
p
=
"sm"
>
<Block
>
<Text
size
=
"xs"
color
=
"secondary"
>
Current
values
</Text
>
<Code
size
=
"sm"
>
{
JSON
.
stringify
(
{
country
,
raw
,
e164
}
,
null
,
2
)
}
</Code
>
</Block
>
</Card
>
</Block
>
)
;
}
Country Formats
Loading demo…
import
{
useState
}
from
'react'
;
import
{
Block
,
Card
,
Code
,
PhoneInput
,
Text
}
from
'@platform-blocks/react-ui-library'
;
export
function
Demo
(
)
{
const
[
us
,
setUs
]
=
useState
(
''
)
;
const
[
uk
,
setUk
]
=
useState
(
''
)
;
const
[
fr
,
setFr
]
=
useState
(
''
)
;
const
[
br
,
setBr
]
=
useState
(
''
)
;
return
(
<Block
fullWidth
>
<Text
weight
=
"semibold"
>
Country
formatting
</Text
>
<Text
size
=
"sm"
color
=
"secondary"
>
Compare
built
-
in masks
for
several countries
.
Each
input stores digits only
while
rendering a localized format
.
</Text
>
<Block
>
<PhoneInput
label
=
"United States"
country
=
"US"
value
=
{
us
}
onChange
=
{
(
raw
)
=>
setUs
(
raw
)
}
showCountryCode
/>
<PhoneInput
label
=
"United Kingdom"
country
=
"GB"
value
=
{
uk
}
onChange
=
{
(
raw
)
=>
setUk
(
raw
)
}
showCountryCode
/>
<PhoneInput
label
=
"France"
country
=
"FR"
value
=
{
fr
}
onChange
=
{
(
raw
)
=>
setFr
(
raw
)
}
showCountryCode
/>
<PhoneInput
label
=
"Brazil"
country
=
"BR"
value
=
{
br
}
onChange
=
{
(
raw
)
=>
setBr
(
raw
)
}
showCountryCode
/>
</Block
>
<Card
variant
=
"outline"
p
=
"sm"
>
<Block
>
<Text
size
=
"xs"
color
=
"secondary"
>
Raw
digit values
</Text
>
<Code
size
=
"sm"
>
{
JSON
.
stringify
(
{
us
,
uk
,
fr
,
br
}
,
null
,
2
)
}
</Code
>
</Block
>
</Card
>
</Block
>
)
;
}
Mask Visibility
Loading demo…
import
{
useState
}
from
'react'
;
import
{
Block
,
PhoneInput
,
Text
}
from
'@platform-blocks/react-ui-library'
;
export
function
Demo
(
)
{
const
[
withCountryCode
,
setWithCountryCode
]
=
useState
(
''
)
;
const
[
withoutCountryCode
,
setWithoutCountryCode
]
=
useState
(
''
)
;
return
(
<Block
fullWidth
>
<Text
weight
=
"semibold"
>
Country
code visibility
</Text
>
<Text
size
=
"sm"
color
=
"secondary"
>
Toggle
the country prefix
while
keeping the same underlying digits
.
</Text
>
<Block
>
<Block
>
<PhoneInput
label
=
"With country code"
value
=
{
withCountryCode
}
onChange
=
{
(
raw
)
=>
setWithCountryCode
(
raw
)
}
country
=
"US"
showCountryCode
/>
<Text
size
=
"xs"
color
=
"secondary"
>
Raw
digits
:
{
withCountryCode
||
'—'
}
</Text
>
</Block
>
<Block
>
<PhoneInput
label
=
"Without country code"
value
=
{
withoutCountryCode
}
onChange
=
{
(
raw
)
=>
setWithoutCountryCode
(
raw
)
}
country
=
"US"
showCountryCode
=
{
false
}
/>
<Text
size
=
"xs"
color
=
"secondary"
>
Raw
digits
:
{
withoutCountryCode
||
'—'
}
</Text
>
</Block
>
</Block
>
</Block
>
)
;
}
Validation
Loading demo…
import
{
useMemo
,
useState
}
from
'react'
;
import
{
Block
,
PhoneInput
,
Text
}
from
'@platform-blocks/react-ui-library'
;
export
function
Demo
(
)
{
const
[
usRaw
,
setUsRaw
]
=
useState
(
''
)
;
const
[
usFormatted
,
setUsFormatted
]
=
useState
(
''
)
;
const
[
internationalRaw
,
setInternationalRaw
]
=
useState
(
''
)
;
const
[
internationalFormatted
,
setInternationalFormatted
]
=
useState
(
''
)
;
const
isValidUs
=
useMemo
(
(
)
=>
usRaw
.
length
===
10
,
[
usRaw
]
)
;
const
isValidInternational
=
useMemo
(
(
)
=>
internationalRaw
.
length
>=
7
&&
internationalRaw
.
length
<=
15
,
[
internationalRaw
]
)
;
return
(
<Block
fullWidth
>
<Text
weight
=
"semibold"
>
Validation
states
</Text
>
<Text
size
=
"sm"
color
=
"secondary"
>
Surface
validation messages based on raw digit counts
for
domestic and international numbers
.
</Text
>
<Block
>
<Block
>
<PhoneInput
label
=
"US phone (10 digits required)"
value
=
{
usRaw
}
onChange
=
{
(
raw
,
formatted
)
=>
{
setUsRaw
(
raw
)
;
setUsFormatted
(
formatted
)
;
}
}
country
=
"US"
showCountryCode
error
=
{
usRaw
.
length
>
0
&&
!
isValidUs
?
'Enter a 10-digit US phone number'
:
undefined
}
/>
<Text
size
=
"xs"
color
=
{
isValidUs
||
usRaw
.
length
===
0
?
'success'
:
'error'
}
>
{
usRaw
.
length
===
0
?
'Enter a phone number'
:
isValidUs
?
`✓ ${usFormatted}`
:
`${usRaw.length}/10 digits entered`
}
</Text
>
</Block
>
<Block
>
<PhoneInput
label
=
"International phone (7-15 digits)"
value
=
{
internationalRaw
}
onChange
=
{
(
raw
,
formatted
)
=>
{
setInternationalRaw
(
raw
)
;
setInternationalFormatted
(
formatted
)
;
}
}
defaultCountry
=
"INTL"
autoDetect
showCountryCode
error
=
{
internationalRaw
.
length
>
0
&&
!
isValidInternational
?
'International numbers should be 7-15 digits'
:
undefined
}
/>
<Text
size
=
"xs"
color
=
{
isValidInternational
||
internationalRaw
.
length
===
0
?
'success'
:
'error'
}
>
{
internationalRaw
.
length
===
0
?
'Enter an international phone number'
:
isValidInternational
?
`✓ ${internationalFormatted}`
:
'Adjust to 7-15 digits'
}
</Text
>
</Block
>
</Block
>
</Block
>
)
;
}
Advanced Masking
Loading demo…
import
{
useState
}
from
'react'
;
import
{
Block
,
PhoneInput
,
Text
}
from
'@platform-blocks/react-ui-library'
;
export
function
Demo
(
)
{
const
[
intlRaw
,
setIntlRaw
]
=
useState
(
''
)
;
const
[
intlFormatted
,
setIntlFormatted
]
=
useState
(
''
)
;
const
[
extensionRaw
,
setExtensionRaw
]
=
useState
(
''
)
;
const
[
extensionFormatted
,
setExtensionFormatted
]
=
useState
(
''
)
;
return
(
<Block
fullWidth
>
<Text
weight
=
"semibold"
>
Advanced
masking
</Text
>
<Text
size
=
"sm"
color
=
"secondary"
>
Apply
custom mask patterns to control formatting
for
international numbers and extension fields
.
</Text
>
<Block
>
<PhoneInput
label
=
"International format"
value
=
{
intlRaw
}
onChange
=
{
(
raw
,
formatted
)
=>
{
setIntlRaw
(
raw
)
;
setIntlFormatted
(
formatted
)
;
}
}
autoDetect
=
{
false
}
showCountryCode
=
{
false
}
mask
=
"+00 (000) 000-0000"
placeholder
=
"+44 (7911) 123-456"
/>
<Text
size
=
"xs"
color
=
"secondary"
>
Raw
digits
:
{
intlRaw
||
'—'
}
</Text
>
<Text
size
=
"xs"
color
=
"secondary"
>
Formatted
:
{
intlFormatted
||
'—'
}
</Text
>
</Block
>
<Block
>
<PhoneInput
label
=
"North America with extension"
value
=
{
extensionRaw
}
onChange
=
{
(
raw
,
formatted
)
=>
{
setExtensionRaw
(
raw
)
;
setExtensionFormatted
(
formatted
)
;
}
}
autoDetect
=
{
false
}
showCountryCode
=
{
false
}
mask
=
"000-000-0000 x0000"
placeholder
=
"555-123-4567 x1234"
/>
<Text
size
=
"xs"
color
=
"secondary"
>
Raw
digits
:
{
extensionRaw
||
'—'
}
</Text
>
<Text
size
=
"xs"
color
=
"secondary"
>
Formatted
:
{
extensionFormatted
||
'—'
}
</Text
>
</Block
>
</Block
>
)
;
}
</>
react-ui-library
100+ accessible, themeable components that work seamlessly across iOS, Android, and Web.
A Platform Blocks product.
Quick Links
Resources