CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-phone-number-input

Telephone number input React component with country selection, validation, and formatting capabilities

Pending
Overview
Eval results
Files

framework-integrations.mddocs/

Framework Integrations

Specialized React Phone Number Input components designed for seamless integration with popular React frameworks and form libraries. These components maintain the same core functionality while providing framework-specific APIs and behaviors.

Capabilities

React Hook Form Integration

Components specifically designed for React Hook Form integration with built-in field registration and validation support.

/**
 * React Hook Form compatible phone input with country selection
 * Integrates directly with useForm() hook and Controller component
 */
interface ReactHookFormProps<FormValues extends FieldValues> {
  /** Field name for form registration (required) */
  name: string;
  /** Default phone number value in E.164 format */
  defaultValue?: string;
  /** React Hook Form control object from useForm() */
  control?: Control<FormValues>;
  /** Validation rules object */
  rules?: {
    required?: boolean | string;
    validate?: (value: string) => boolean | string;
    pattern?: RegExp;
    minLength?: number;
    maxLength?: number;
    [key: string]: any;
  };
  /** Unregister field when component unmounts */
  shouldUnregister?: boolean;
  /** All standard phone input props */
  defaultCountry?: Country;
  placeholder?: string;
  disabled?: boolean;
  countries?: Country[];
  labels?: Labels;
  className?: string;
  style?: object;
  onCountryChange?(country?: Country): void;
  // ... all other PhoneInput props supported
}

declare const PhoneInputWithCountrySelect: <FormValues extends FieldValues = FieldValues>(
  props: ReactHookFormProps<FormValues>
) => JSX.Element;

Usage Examples:

import React from "react";
import { useForm, Controller } from "react-hook-form";
import PhoneInput from "react-phone-number-input/react-hook-form";
import "react-phone-number-input/style.css";

interface FormData {
  phoneNumber: string;
  name: string;
}

// Basic React Hook Form integration
function ReactHookFormExample() {
  const { control, handleSubmit, formState: { errors } } = useForm<FormData>();
  
  const onSubmit = (data: FormData) => {
    console.log('Form data:', data);
    console.log('Phone number:', data.phoneNumber); // E.164 format
  };
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <PhoneInput
        name="phoneNumber"
        control={control}
        defaultCountry="US"
        placeholder="Enter phone number"
        rules={{
          required: "Phone number is required",
          validate: (value) => 
            value && value.length > 5 || "Please enter a valid phone number"
        }}
      />
      {errors.phoneNumber && (
        <span className="error">{errors.phoneNumber.message}</span>
      )}
      <button type="submit">Submit</button>
    </form>
  );
}

// With FormProvider (no control prop needed)
function FormProviderExample() {
  const methods = useForm<FormData>();
  
  return (
    <FormProvider {...methods}>
      <form onSubmit={methods.handleSubmit(console.log)}>
        <PhoneInput
          name="phoneNumber"
          defaultCountry="US"
          rules={{ required: true }}
        />
      </form>
    </FormProvider>
  );
}

// Custom validation
function CustomValidationExample() {
  const { control, handleSubmit } = useForm<FormData>();
  
  const validatePhoneNumber = (value: string) => {
    if (!value) return "Phone number is required";
    if (!value.startsWith("+1")) return "Please enter a US phone number";
    if (value.length < 12) return "Phone number appears incomplete";
    return true;
  };
  
  return (
    <form onSubmit={handleSubmit(console.log)}>
      <PhoneInput
        name="phoneNumber"
        control={control}
        defaultCountry="US"
        countries={["US", "CA"]}
        rules={{ validate: validatePhoneNumber }}
      />
    </form>
  );
}

React Hook Form Input-Only Integration

Input-only version for React Hook Form without country selection.

/**
 * React Hook Form compatible input-only phone component
 * Provides the same React Hook Form integration without country dropdown
 */
interface ReactHookFormInputProps<FormValues extends FieldValues> 
  extends ReactHookFormProps<FormValues> {
  /** Specific country for national formatting */
  country?: Country;
  /** Force international format */
  international?: boolean;
  /** Include country calling code when international=true */
  withCountryCallingCode?: boolean;
  /** Default country for ambiguous numbers */
  defaultCountry?: Country;
  /** Custom input component */
  inputComponent?: React.ElementType;
  /** Enable smart caret positioning */
  smartCaret?: boolean;
}

declare const PhoneInput: <FormValues extends FieldValues = FieldValues>(
  props: ReactHookFormInputProps<FormValues>
) => JSX.Element;

Usage Example:

import PhoneInput from "react-phone-number-input/react-hook-form-input";

function ReactHookFormInputExample() {
  const { control, handleSubmit } = useForm();
  
  return (
    <form onSubmit={handleSubmit(console.log)}>
      <PhoneInput
        name="phoneNumber"
        control={control}
        country="US"
        placeholder="(555) 123-4567"
        rules={{ required: "Phone number is required" }}
      />
    </form>
  );
}

React Hook Form Core Variants

Core versions requiring manual metadata for smaller bundle sizes.

// React Hook Form with country select (core)
import PhoneInput from "react-phone-number-input/react-hook-form-core";

// React Hook Form input-only (core)  
import PhoneInput from "react-phone-number-input/react-hook-form-input-core";

interface ReactHookFormCoreProps<FormValues> 
  extends ReactHookFormProps<FormValues> {
  /** libphonenumber-js metadata object (required) */
  metadata: Metadata;
  /** Localization labels (required) */
  labels: Labels;
}

React Native Integration

Specialized component for React Native applications.

/**
 * React Native compatible phone input component
 * Optimized for mobile interfaces and React Native TextInput
 */
interface ReactNativeInputProps {
  /** Phone number value in E.164 format */
  value?: string;
  /** Called when phone number changes */
  onChange(value?: string): void;
  /** Specific country for national formatting */
  country?: Country;
  /** Force international format */
  international?: boolean;
  /** Include country calling code */
  withCountryCallingCode?: boolean;
  /** Default country for ambiguous numbers */
  defaultCountry?: Country;
  /** Custom TextInput component */
  inputComponent?: React.ElementType;
  /** React Native TextInput props */
  placeholder?: string;
  editable?: boolean;
  autoFocus?: boolean;
  keyboardType?: 'phone-pad' | 'number-pad' | 'default';
  returnKeyType?: string;
  onFocus?(event: any): void;
  onBlur?(event: any): void;
  style?: any;
  // ... other React Native TextInput props
}

declare const PhoneInput: React.ForwardRefExoticComponent<ReactNativeInputProps>;

Usage Example:

import React, { useState } from "react";
import { View } from "react-native";
import PhoneInput from "react-phone-number-input/react-native-input";

function ReactNativeExample() {
  const [phoneNumber, setPhoneNumber] = useState();
  
  return (
    <View>
      <PhoneInput
        value={phoneNumber}
        onChange={setPhoneNumber}
        defaultCountry="US"
        placeholder="Enter phone number"
        keyboardType="phone-pad"
        style={{ 
          height: 40, 
          borderColor: 'gray', 
          borderWidth: 1,
          paddingHorizontal: 10
        }}
      />
    </View>
  );
}

Field Values Type System

Framework integrations provide proper TypeScript support for form values.

// React Hook Form field values constraint
interface FieldValues {
  [key: string]: any;
}

// Default form values type
type DefaultFormValues = FieldValues;

// Control type from React Hook Form
interface Control<FormValues extends FieldValues> {
  register: (name: keyof FormValues, options?: any) => any;
  unregister: (name: keyof FormValues) => void;
  formState: FormState<FormValues>;
  watch: (name?: keyof FormValues) => any;
  // ... other Control methods
}

Error Handling and Validation

Framework integrations handle validation and error states consistently.

// Validation rules interface
interface ValidationRules {
  required?: boolean | string;
  min?: number | { value: number; message: string };
  max?: number | { value: number; message: string };
  minLength?: number | { value: number; message: string };
  maxLength?: number | { value: number; message: string };
  pattern?: RegExp | { value: RegExp; message: string };
  validate?: 
    | ((value: any) => boolean | string)
    | Record<string, (value: any) => boolean | string>;
}

// Form state for error handling
interface FormState<FormValues> {
  errors: Record<keyof FormValues, { message?: string; type?: string }>;
  isDirty: boolean;
  isValid: boolean;
  isSubmitting: boolean;
  // ... other form state properties
}

Validation Examples:

// Phone number specific validation
const phoneValidationRules = {
  required: "Phone number is required",
  validate: {
    validFormat: (value: string) => 
      !value || value.startsWith('+') || "Phone number must be in international format",
    usNumber: (value: string) => 
      !value || value.startsWith('+1') || "Please enter a US phone number",
    minLength: (value: string) => 
      !value || value.length >= 12 || "Phone number appears to be too short"
  }
};

function ValidationExample() {
  const { control, formState: { errors } } = useForm();
  
  return (
    <>
      <PhoneInput
        name="phoneNumber"
        control={control}
        rules={phoneValidationRules}
        defaultCountry="US"
      />
      {errors.phoneNumber && (
        <span className="error">
          {errors.phoneNumber.message}
        </span>
      )}
    </>
  );
}

shouldUnregister Behavior

Framework integrations support the shouldUnregister option for proper form cleanup.

interface UnregisterBehavior {
  /** 
   * Controls whether field value is retained when component unmounts
   * true: field is unregistered and value is removed (recommended)
   * false: field value is retained even after unmount
   */
  shouldUnregister?: boolean;
}

This affects form behavior when phone input components are conditionally rendered or removed from the DOM.

Install with Tessl CLI

npx tessl i tessl/npm-react-phone-number-input

docs

customization.md

framework-integrations.md

index.md

input-components.md

internationalization.md

phone-input-components.md

utility-functions.md

tile.json