npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@foodhubglobal/phone

v0.1.12

Published

Phone number parsing, formatting and validation utilities built on libphonenumber-js, with TypeScript types and dual CommonJS/ES module builds for React Native, React and Node.js.

Readme

@foodhubglobal/phone

Phone number parsing, formatting and validation utilities built on libphonenumber-js, with TypeScript types and dual CommonJS/ES module builds.

Runs anywhere JavaScript does — React Native, React, Node.js and the browser. The package has no React or React Native dependency.

Installation

npm install @foodhubglobal/phone
# or
yarn add @foodhubglobal/phone

Usage in Different Environments

This library is compatible with multiple JavaScript/TypeScript environments. The phone module is a pure utility library that works in any JavaScript runtime.

1. React Native App

// App.tsx or any component file
import { 
  formatPhoneNumber, 
  validatePhoneNumber,
  formatAsYouType 
} from '@foodhubglobal/phone';

// Usage in React Native component
import React, { useState } from 'react';
import { TextInput, View, Text } from 'react-native';

function PhoneInput() {
  const [phone, setPhone] = useState('');

  return (
    <View>
      <TextInput
        value={phone}
        onChangeText={(text) => setPhone(formatAsYouType(text, 'US'))}
        placeholder="Enter phone number"
      />
      {validatePhoneNumber(phone, 'US') && (
        <Text>Formatted: {formatPhoneNumber(phone, 'US')}</Text>
      )}
    </View>
  );
}

2. React.js (Web Application)

// Component.tsx or any React component
import { 
  formatPhoneNumber, 
  validatePhoneNumber,
  formatAsYouType 
} from '@foodhubglobal/phone';

// Usage in React component
import React, { useState } from 'react';

function PhoneInput() {
  const [phone, setPhone] = useState('');

  return (
    <div>
      <input
        type="tel"
        value={phone}
        onChange={(e) => setPhone(formatAsYouType(e.target.value, 'US'))}
        placeholder="Enter phone number"
      />
      {validatePhoneNumber(phone, 'US') && (
        <p>Formatted: {formatPhoneNumber(phone, 'US')}</p>
      )}
    </div>
  );
}

3. Node.js (API/Server Layer)

CommonJS (require)

// server.js or api.js
const { 
  formatPhoneNumber, 
  validatePhoneNumber,
  parsePhone 
} = require('@foodhubglobal/phone');

// Usage in Express.js API route
const express = require('express');
const app = express();

app.post('/validate-phone', (req, res) => {
  const { phone, country } = req.body;
  
  if (validatePhoneNumber(phone, country)) {
    const formatted = formatPhoneNumber(phone, country);
    res.json({ valid: true, formatted });
  } else {
    res.status(400).json({ valid: false, error: 'Invalid phone number' });
  }
});

// Usage with detailed parsing
app.get('/parse-phone/:phone', (req, res) => {
  const result = parsePhone(req.params.phone, req.query.country);
  res.json(result);
});

ES Modules (import) - Node.js 12+ or with "type": "module"

// server.mjs or package.json has "type": "module"
import { 
  formatPhoneNumber, 
  validatePhoneNumber,
  parsePhone 
} from '@foodhubglobal/phone';

// Usage in Express.js API route (ES Modules)
import express from 'express';
const app = express();

app.post('/validate-phone', (req, res) => {
  const { phone, country } = req.body;
  
  if (validatePhoneNumber(phone, country)) {
    const formatted = formatPhoneNumber(phone, country);
    res.json({ valid: true, formatted });
  } else {
    res.status(400).json({ valid: false, error: 'Invalid phone number' });
  }
});

TypeScript in Node.js

// api.ts or server.ts
import { 
  formatPhoneNumber, 
  validatePhoneNumber,
  parsePhone,
  type CountryCode 
} from '@foodhubglobal/phone';

// Usage in Express.js API route (TypeScript)
import express, { Request, Response } from 'express';
const app = express();

app.post('/validate-phone', (req: Request, res: Response) => {
  const { phone, country }: { phone: string; country?: CountryCode } = req.body;
  
  if (validatePhoneNumber(phone, country)) {
    const formatted = formatPhoneNumber(phone, country);
    res.json({ valid: true, formatted });
  } else {
    res.status(400).json({ valid: false, error: 'Invalid phone number' });
  }
});

4. Pure JavaScript Project (Browser/Vanilla JS)

HTML with Script Tag (Browser)

<!-- Note: You'll need to bundle this first or use a CDN/bundler -->
<!DOCTYPE html>
<html>
<head>
  <title>Phone Formatter</title>
</head>
<body>
  <input type="tel" id="phoneInput" placeholder="Enter phone number">
  <button onclick="formatPhone()">Format</button>
  <p id="result"></p>

  <script type="module">
    // If using ES modules in browser
    import { formatPhoneNumber, validatePhoneNumber } from './node_modules/@foodhubglobal/phone/lib/module/index.js';
    
    window.formatPhone = function() {
      const input = document.getElementById('phoneInput');
      const result = document.getElementById('result');
      const phone = input.value;
      
      if (validatePhoneNumber(phone, 'US')) {
        result.textContent = `Formatted: ${formatPhoneNumber(phone, 'US')}`;
      } else {
        result.textContent = 'Invalid phone number';
      }
    };
  </script>
</body>
</html>

Bundled JavaScript (Webpack/Rollup/Vite)

// app.js - Works with any bundler (Webpack, Rollup, Vite, etc.)
import { 
  formatPhoneNumber, 
  validatePhoneNumber 
} from '@foodhubglobal/phone';

// Usage
function formatPhone(phoneNumber) {
  if (validatePhoneNumber(phoneNumber, 'US')) {
    return formatPhoneNumber(phoneNumber, 'US');
  }
  return 'Invalid phone number';
}

// Export for use in other files
export { formatPhone };

Node.js Script (CLI/Tooling)

// script.js - Run with: node script.js
const { formatPhoneNumber, validatePhoneNumber } = require('@foodhubglobal/phone');

// CLI usage
const phoneNumber = process.argv[2];
const country = process.argv[3] || 'US';

if (validatePhoneNumber(phoneNumber, country)) {
  console.log(`Valid! Formatted: ${formatPhoneNumber(phoneNumber, country)}`);
} else {
  console.log('Invalid phone number');
  process.exit(1);
}

Modules

Phone Module

A comprehensive phone number formatting and validation module built on top of libphonenumber-js. Provides utilities for formatting, validating, and parsing phone numbers from around the world.

Installation

The phone module is included in the main package. No additional installation required.

Usage

import { 
  formatPhoneNumber, 
  formatInternational, 
  validatePhoneNumber,
  formatAsYouType 
} from '@foodhubglobal/phone';

Examples

Format Phone Numbers

import { formatPhoneNumber, formatInternational, formatNational } from '@foodhubglobal/phone';

// E.164 format (default)
// With country code parameter (recommended for national numbers)
formatPhoneNumber('2125551234', 'US'); // => '+12125551234'

// Without country code (works when number includes country prefix)
formatPhoneNumber('+12125551234'); // => '+12125551234'
formatPhoneNumber('+442071234567'); // => '+442071234567'

// Fallback: Without country code for national number (returns original phoneNumber)
formatPhoneNumber('2125551234'); // => '2125551234' (returns original if parsing fails)

// With fallback parameter
formatPhoneNumber('invalid', undefined, 'N/A'); // => 'N/A' (returns fallback)
formatPhoneNumber('invalid'); // => 'invalid' (returns original phoneNumber)

// International format
formatInternational('2125551234', 'US'); // => '+1 212 555 1234'
formatInternational('02071234567', 'GB'); // => '+44 20 7123 4567'
formatInternational('+12125551234'); // => '+1 212 555 1234'
formatInternational('invalid', undefined, 'N/A'); // => 'N/A' (returns fallback)

// National format
formatNational('2125551234', 'US'); // => '(212) 555-1234'
formatNational('02071234567', 'GB'); // => '020 7123 4567'
formatNational('+12125551234'); // => '(212) 555-1234'
formatNational('invalid', undefined, 'N/A'); // => 'N/A' (returns fallback)

Important: For national numbers (without country code prefix like +1), always provide the countryCode parameter for accurate results.

Error Handling: All format functions now support an optional fallback parameter. If parsing fails:

  • With fallback provided: returns the fallback value
  • Without fallback: returns the original phoneNumber (for format functions) or undefined (for extract/get functions)

Validate Phone Numbers

import { validatePhoneNumber, isPossibleNumber } from '@foodhubglobal/phone';

validatePhoneNumber('+12125551234'); // => true
validatePhoneNumber('2125551234', 'US'); // => true
validatePhoneNumber('123', 'US'); // => false

isPossibleNumber('2125551234', 'US'); // => true
isPossibleNumber('123', 'US'); // => false

As-You-Type Formatting

import { formatAsYouType } from '@foodhubglobal/phone';

// With country code parameter (recommended)
formatAsYouType('212', 'US'); // => '(212)'
formatAsYouType('212555', 'US'); // => '(212) 555'
formatAsYouType('2125551234', 'US'); // => '(212) 555-1234'

// Without country code (works when input includes country prefix)
formatAsYouType('+1212'); // => '+1 212'
formatAsYouType('+442071234567'); // => '+44 20 7123 4567'

// Use in TextInput for real-time formatting
<TextInput
  value={phoneNumber}
  onChangeText={(text) => setPhoneNumber(formatAsYouType(text, 'US'))}
/>

Parse Phone Numbers

import { parsePhone } from '@foodhubglobal/phone';

// With country code parameter (recommended for national numbers)
const result1 = parsePhone('2125551234', 'US');
// => {
//   isValid: true,
//   isPossible: true,
//   country: 'US',
//   countryCallingCode: '1',
//   nationalNumber: '2125551234',
//   internationalFormat: '+1 212 555 1234',
//   nationalFormat: '(212) 555-1234',
//   e164Format: '+12125551234'
// }

// Without country code (works when number includes country prefix)
const result2 = parsePhone('+12125551234');
// => { ... same structure as above ... }

// Fallback: Without country code for national number (returns error object)
const result3 = parsePhone('2125551234');
// => {
//   isValid: false,
//   isPossible: false
// }

Get Country Information

import { 
  getCountryFromPhoneNumber, 
  getCallingCode, 
  getAvailableCountries 
} from '@foodhubglobal/phone';

getCountryFromPhoneNumber('+12125551234'); // => 'US'
getCountryFromPhoneNumber('+442071234567'); // => 'GB'
getCountryFromPhoneNumber('invalid', 'US'); // => 'US' (returns fallback)

getCallingCode('US'); // => '1'
getCallingCode('GB'); // => '44'
getCallingCode('IN'); // => '91'
getCallingCode('INVALID', 'N/A'); // => 'N/A' (returns fallback)

getAvailableCountries(); // => ['US', 'GB', 'CA', 'AU', 'IN', ...]

Extract Phone Numbers

import { extractPhoneNumber } from '@foodhubglobal/phone';

extractPhoneNumber('Call me at +12125551234'); // => '+12125551234'
extractPhoneNumber('2125551234', 'US'); // => '+12125551234'
extractPhoneNumber('No phone here', undefined, 'N/A'); // => 'N/A' (returns fallback)
extractPhoneNumber('No phone here'); // => undefined (no fallback provided)

Number Type Detection

import { 
  getNumberType, 
  isMobileNumber, 
  isFixedLineNumber 
} from '@foodhubglobal/phone';

getNumberType('+12125551234'); // => 'MOBILE' | 'FIXED_LINE' | 'VOIP' | etc.
isMobileNumber('+12125551234'); // => true | false
isFixedLineNumber('+12125551234'); // => true | false

Additional Utilities

import { 
  normalizePhoneNumber,
  formatIncomplete,
  getNationalNumber,
  getCallingCodeFromNumber,
  isSameNumber,
  isValidForCountry,
  formatRFC3966,
  format
} from '@foodhubglobal/phone';

// Normalize phone number
normalizePhoneNumber('(212) 555-1234', 'US'); // => '+12125551234'
normalizePhoneNumber('invalid', undefined, 'N/A'); // => 'N/A' (returns fallback)

// Format incomplete numbers
formatIncomplete('212', 'US'); // => '(212)'

// Get national number
getNationalNumber('+12125551234'); // => '2125551234'
getNationalNumber('invalid', undefined, 'N/A'); // => 'N/A' (returns fallback)
getNationalNumber('invalid'); // => undefined (no fallback provided)

// Get calling code from number
getCallingCodeFromNumber('+12125551234'); // => '1'
getCallingCodeFromNumber('invalid', 'N/A'); // => 'N/A' (returns fallback)
getCallingCodeFromNumber('invalid'); // => undefined (no fallback provided)

// Compare two numbers
isSameNumber('+12125551234', '(212) 555-1234', 'US'); // => true

// Validate for specific country
isValidForCountry('2125551234', 'US'); // => true

// RFC3966 format
formatRFC3966('2125551234', 'US'); // => 'tel:+1-212-555-1234'
formatRFC3966('invalid', undefined, 'N/A'); // => 'N/A' (returns fallback)

// Custom format
format('2125551234', 'E.164', 'US'); // => '+12125551234'
format('2125551234', 'INTERNATIONAL', 'US'); // => '+1 212 555 1234'
format('invalid', 'E.164', undefined, 'N/A'); // => 'N/A' (returns fallback)

Supported Countries

The phone module supports all countries supported by libphonenumber-js. Use getAvailableCountries() to get the full list of supported country codes.

Best Practices

When to provide countryCode parameter:

  • ✅ Always provide when working with national numbers (e.g., '2125551234')
  • ✅ Optional when the number includes a country code prefix (e.g., '+12125551234')
  • ✅ Recommended for all formatting and validation functions to ensure accuracy

Example:

// ✅ Good: National number with country code
formatPhoneNumber('2125551234', 'US'); // => '+12125551234'

// ✅ Good: International format with prefix
formatPhoneNumber('+12125551234'); // => '+12125551234'

// ⚠️ May fail: National number without country code
formatPhoneNumber('2125551234'); // => undefined (ambiguous)

Troubleshooting: Validation works in Staging but not Production

If phone validation behaves differently in production than in staging, check the following:

  1. Pass countryCode in both environments
    National numbers (without a + prefix) require a country code. If prod uses a different config or API and omits countryCode, validation will fail. Prefer always passing it:
    validatePhoneNumber(phone, countryCode).

  2. Country code format
    Use ISO 3166-1 alpha-2 (e.g. 'US', 'GB'). The library normalizes lowercase (e.g. 'us' → 'US'). Ensure prod is not sending a different format (e.g. numeric or 3-letter).

  3. Input normalization
    The library trims whitespace and normalizes common Unicode digits to ASCII. If prod receives numbers from another system (e.g. with leading/trailing spaces or non-ASCII digits), they are normalized before validation. If you still see differences, log the exact phoneNumber and countryCode in prod and compare to staging.

  4. Dependency version
    Ensure staging and prod resolve the same version of @foodhubglobal/phone (and thus libphonenumber-js). Lockfiles and install scripts should be identical so production does not get an older build.

TypeScript Support

The module is fully typed with TypeScript. All functions include comprehensive type definitions and JSDoc comments for better IDE support, including detailed parameter descriptions and fallback behavior documentation.

import type { CountryCode, NumberFormat, NumberType } from '@foodhubglobal/phone';

Quick Reference: Import Methods

Depending on your environment, use the appropriate import method:

| Environment | CommonJS (require) | ES Modules (import) | |------------|-------------------|---------------------| | Node.js | ✅ require('@foodhubglobal/phone') | ✅ import from '@foodhubglobal/phone' | | React.js | ✅ require('@foodhubglobal/phone') (ESM preferred) | ✅ import from '@foodhubglobal/phone' | | React Native | ✅ require('@foodhubglobal/phone') (ESM preferred) | ✅ import from '@foodhubglobal/phone' | | Pure JavaScript | ✅ require(...) | ✅ import from ... |

Note: These utilities are pure JavaScript functions. The package has no React or React Native dependency, so it can be used in any JavaScript environment. In React.js and React Native projects, bundlers such as Metro and common React build setups typically support both CommonJS (require) and ES modules (import); ES modules are recommended for new code, but CommonJS remains fully functional in these environments.

IDE Features:

  • Auto-completion for all functions
  • Inline documentation with JSDoc comments
  • Type checking for parameters and return values
  • Examples in tooltips

API Reference

Phone Module Functions

| Function | Description | Parameters | Returns | |----------|-------------|------------|---------| | formatPhoneNumber(phone, country?, fallback?) | Format in E.164 format | phone: string, country?: CountryCode, fallback?: string | string \| undefined | | formatInternational(phone, country?, fallback?) | Format in international format | phone: string, country?: CountryCode, fallback?: string | string \| undefined | | formatNational(phone, country?, fallback?) | Format in national format | phone: string, country?: CountryCode, fallback?: string | string \| undefined | | validatePhoneNumber(phone, country?) | Validate phone number | phone: string, country?: CountryCode | boolean | | isPossibleNumber(phone, country?) | Check if number is possible | phone: string, country?: CountryCode | boolean | | formatAsYouType(phone, country?) | Format as user types | phone: string, country?: CountryCode | string | | parsePhone(phone, country?) | Parse and get detailed info | phone: string, country?: CountryCode | object | | getCountryFromPhoneNumber(phone, fallback?) | Extract country from number | phone: string (must include country prefix), fallback?: CountryCode | CountryCode \| undefined | | getCallingCode(country, fallback?) | Get calling code for country | country: CountryCode, fallback?: string | string \| undefined | | getAvailableCountries() | Get all supported countries | None | CountryCode[] | | extractPhoneNumber(text, country?, fallback?) | Extract number from text | text: string, country?: CountryCode, fallback?: string | string \| undefined | | getNumberType(phone, country?) | Get number type | phone: string, country?: CountryCode | NumberType \| undefined | | isMobileNumber(phone, country?) | Check if mobile number | phone: string, country?: CountryCode | boolean | | isFixedLineNumber(phone, country?) | Check if fixed-line number | phone: string, country?: CountryCode | boolean | | normalizePhoneNumber(phone, country?, fallback?) | Normalize to E.164 | phone: string, country?: CountryCode, fallback?: string | string \| undefined | | formatIncomplete(phone, country?) | Format incomplete number | phone: string, country?: CountryCode | string | | getNationalNumber(phone, country?, fallback?) | Get national number | phone: string, country?: CountryCode, fallback?: string | string \| undefined | | getCallingCodeFromNumber(phone, fallback?) | Get calling code from number | phone: string (must include country prefix), fallback?: string | string \| undefined | | isSameNumber(phone1, phone2, country?) | Compare two numbers | phone1: string, phone2: string, country?: CountryCode | boolean | | isValidForCountry(phone, country) | Validate for country | phone: string, country: CountryCode | boolean | | formatRFC3966(phone, country?, fallback?) | Format in RFC3966 | phone: string, country?: CountryCode, fallback?: string | string \| undefined | | format(phone, formatType, country?, fallback?) | Format with custom format | phone: string, formatType: NumberFormat, country?: CountryCode, fallback?: string | string \| undefined |

Note:

  • The country? parameter is optional but highly recommended for national numbers (without country code prefix). When omitted for national numbers, functions may return undefined or error objects due to ambiguity. For numbers with country code prefix (e.g., +1...), the parameter is optional and the country is auto-detected.
  • The fallback? parameter is optional and provides error handling:
    • Format functions (formatPhoneNumber, formatInternational, formatNational, formatRFC3966, format, normalizePhoneNumber): If parsing fails and fallback is provided, returns fallback; otherwise returns the original phoneNumber.
    • Extract/Get functions (extractPhoneNumber, getNationalNumber, getCallingCodeFromNumber, getCountryFromPhoneNumber, getCallingCode): If parsing fails and fallback is provided, returns fallback; otherwise returns undefined.
    • Parse function (parsePhone): Returns an object with isValid: false, isPossible: false when parsing fails (never returns null).

Contributing

License

Proprietary. Copyright (c) 2025-2026 Foodhub. All rights reserved.

This package is licensed, not sold. You may install it and use it as a dependency within your own applications. You may not modify it, redistribute it on a standalone basis, or reverse engineer it. See LICENSE for the full terms.


Made with create-react-native-library