PhoneInput

A formatted phone number input with international support

A specialized phone number input component with automatic formatting, country selection, and international support. Perfect for collecting phone numbers in forms.

Overview

PhoneInput handles phone number formatting automatically and provides a country picker for international support. It manages validation, formatting, and provides a clean UX for phone entry.

Use it for:

  • User registration and signup forms
  • Contact information collection
  • Call or SMS features
  • Appointment booking forms
  • Two-factor authentication
  • Profile updates

Basic Usage

import { PhoneInput } from 'prizmux'
import { useState } from 'react'
import { View } from 'react-native'

export default function SignUpForm() {
  const [phoneData, setPhoneData] = useState(null)

  return (
    <View style={{ padding: 16 }}>
      <PhoneInput
        onChange={(value) => setPhoneData(value)}
        placeholder="712 345 678"
      />
    </View>
  )
}

With Default Country

import { PhoneInput } from 'prizmux'

<PhoneInput
  defaultCountryCode="GB"
  onChange={(value) => console.log(value)}
  placeholder="7700 900000"
/>

Restricted Countries

import { PhoneInput } from 'prizmux'

<PhoneInput
  defaultCountryCode="UG"
  allowedCountries={['UG', 'KE', 'TZ', 'RW']}
  onChange={(value) => console.log(value)}
/>

With Label and Error

import { PhoneInput } from 'prizmux'
import { useState } from 'react'
import { View, Text } from 'react-native'

export default function ContactForm() {
  const [phoneData, setPhoneData] = useState(null)
  const [error, setError] = useState('')

  const handlePhoneChange = (value) => {
    setPhoneData(value)
    // Validate
    if (value.full && value.full.length < 10) {
      setError('Phone number too short')
    } else {
      setError('')
    }
  }

  return (
    <View style={{ gap: 12 }}>
      <Text style={{ fontSize: 16, fontWeight: '600' }}>Phone Number</Text>
      <PhoneInput
        value={phoneData}
        onChange={handlePhoneChange}
        label="Mobile Phone"
        error={error}
        placeholder="Enter phone number"
      />
      {error && <Text style={{ color: '#EF4444' }}>{error}</Text>}
    </View>
  )
}

Form Integration

import { PhoneInput, Button } from 'prizmux'
import { useState } from 'react'
import { View, Text } from 'react-native'

export default function RegistrationForm() {
  const [phoneData, setPhoneData] = useState(null)
  const [loading, setLoading] = useState(false)

  const handleSubmit = async () => {
    if (!phoneData?.full) {
      alert('Please enter a phone number')
      return
    }

    setLoading(true)
    try {
      await submitPhoneNumber(phoneData.full)
      alert('Phone number submitted!')
    } catch (error) {
      alert('Error: ' + error.message)
    } finally {
      setLoading(false)
    }
  }

  return (
    <View style={{ gap: 16, padding: 16 }}>
      <PhoneInput
        value={phoneData}
        onChange={setPhoneData}
        placeholder="Enter your phone number"
      />
      
      <Button
        title="Verify Phone"
        isLoading={loading}
        fullWidth={true}
        onPress={handleSubmit}
      />
    </View>
  )
}

Accessing Phone Data

The onChange callback receives a PhoneInputValue object with three properties:

interface PhoneInputValue {
  country: Country          // Country object with code and dial info
  number: string           // Local number without dial code
  full: string            // Full number with dial code (e.g. "+254712345678")
}

// Usage
<PhoneInput
  onChange={(value) => {
    console.log(value.country.code)    // 'UG'
    console.log(value.number)          // '712345678'
    console.log(value.full)            // '+256712345678'
  }}
/>

Custom Flag Rendering

import { PhoneInput } from 'prizmux'

<PhoneInput
  onChange={(value) => {}}
  renderFlag={(country) => (
    <Text style={{ fontSize: 24, marginRight: 8 }}>
      {country.code === 'US' ? '🇺🇸' : '🌍'}
    </Text>
  )}
/>

Props Reference

PropTypeDefaultDescription
valuePhoneInputValue-Current phone data
onChange(value: PhoneInputValue) => voidRequiredCalled when value changes
defaultCountryCodestring'US'Initial country code
allowedCountriesstring[]-Restrict to specific countries
placeholderstring'712 345 678'Input placeholder
labelstring-Input label
errorstring-Error message
disabledbooleanfalseDisable input
pickerTitlestring'Select Country'Country picker title
searchPlaceholderstring-Country search placeholder
dropdownIconReactNode-Custom dropdown icon
renderFlag(country) => ReactNode-Custom flag rendering
containerStyleViewStyle-Container styles
inputStyleTextStyle-Input field styles
labelStyleTextStyle-Label text styles
errorStyleTextStyle-Error text styles

Features

  • 🌍 International country support
  • 🎯 Automatic formatting and detection
  • 🔍 Country search and filtering
  • 🎨 Customizable styles and icons
  • ✅ Full TypeScript support
  • ♿ Accessibility support

Usage

Basic Phone Input

import { PhoneInput } from 'prizmux'
import { useState } from 'react'

export default function SignUp() {
  const [phone, setPhone] = useState('')

  return (
    <PhoneInput
      value={phone}
      onChange={setPhone}
      placeholder="Enter phone number"
    />
  )
}

With Default Country

<PhoneInput
  value={phone}
  onChange={setPhone}
  defaultCountry="GB"
  placeholder="+44"
/>

With Country Change Handling

import { PhoneInput } from 'prizmux'
import { useState } from 'react'

export default function ContactForm() {
  const [phone, setPhone] = useState('')
  const [country, setCountry] = useState('US')

  return (
    <>
      <PhoneInput
        value={phone}
        onChange={setPhone}
        defaultCountry={country}
        onCountryChange={setCountry}
      />
      <Text>Country Code: {country}</Text>
    </>
  )
}

Form Integration

import { PhoneInput, Button, Text } from 'prizmux'
import { useState } from 'react'
import { View } from 'react-native'

export default function RegistrationForm() {
  const [phone, setPhone] = useState('')
  const [error, setError] = useState('')
  const [loading, setLoading] = useState(false)

  const validatePhone = (value) => {
    if (!value) {
      setError('Phone number is required')
      return false
    }
    if (value.length < 10) {
      setError('Phone number is too short')
      return false
    }
    setError('')
    return true
  }

  const handleSubmit = async () => {
    if (!validatePhone(phone)) return

    setLoading(true)
    try {
      await registerPhone(phone)
      // Success
    } catch (err) {
      setError(err.message)
    } finally {
      setLoading(false)
    }
  }

  return (
    <View style={{ gap: 16 }}>
      <PhoneInput
        value={phone}
        onChange={setPhone}
        error={error}
        placeholder="Phone number"
      />
      {error && <Text style={{ color: 'red' }}>{error}</Text>}
      <Button
        title="Verify"
        loading={loading}
        onPress={handleSubmit}
      />
    </View>
  )
}

Two-Factor Authentication

import { PhoneInput, Button, Text } from 'prizmux'
import { useState } from 'react'
import { View } from 'react-native'

export default function TwoFactorSetup() {
  const [phone, setPhone] = useState('')
  const [verified, setVerified] = useState(false)

  const handleSendCode = async () => {
    const result = await sendVerificationCode(phone)
    if (result.success) {
      setVerified(true)
      // Navigate to code verification screen
    }
  }

  return (
    <View style={{ gap: 16 }}>
      <Text variant="title">Add Phone Number</Text>
      <Text variant="caption">
        We'll send you a code to verify
      </Text>
      
      <PhoneInput
        value={phone}
        onChange={setPhone}
        placeholder="Phone number"
        disabled={verified}
      />
      
      {!verified && (
        <Button
          title="Send Code"
          onPress={handleSendCode}
        />
      )}
    </View>
  )
}

International Numbers

import { PhoneInput } from 'prizmux'

// Automatically formats based on country
<PhoneInput
  value={phone}
  onChange={setPhone}
  defaultCountry="DE"
  // Shows German format: +49 XXXX XXXX
/>

<PhoneInput
  value={phone}
  onChange={setPhone}
  defaultCountry="JP"
  // Shows Japanese format: +81 XX XXXX XXXX
/>

Formatting

PhoneInput automatically formats numbers based on selected country:

  • US: (123) 456-7890
  • UK: +44 1632 960291
  • Germany: +49 30 11001100
  • France: +33 1 42 68 53 00
  • Others: International format maintained

Notes

  • Automatically adds country code prefix
  • Handles paste events with auto-formatting
  • Validates format in real-time
  • Supports all country codes
  • Keyboard type set to phone-pad automatically
  • Error state integrated for form validation
  • International format compliance