Zero runtime dependencies. Helpers for compact E.164 storage (+ + country calling code + national digits without a leading national zero), syntax checks aligned with common international practice, national length checks against embedded coarse ranges (with optional hand-tuned overrides), and picker data with English default labels plus bundled partial translations (Arabic, French, Spanish, German, Portuguese, Urdu, Hindi, Turkish, Russian).
If your GitHub repo URL differs from /e164-compact, update repository / homepage in package.json and the badge URLs above so npm and CI badges stay accurate.
| Need | e164-compact |
Heavier full-feature phone stacks |
|---|---|---|
| Install size / tree | Small, no runtime deps | Often large metadata + parsing logic |
| Goal | Normalize + validate shape/length for storage | Full carrier/type rules, formatting everywhere |
| Data in repo | Plain src/data/*.ts you can PR |
Often generated blobs or vendored copies |
Use this when you want a predictable normalization path for APIs and databases, optional strict errors for bad input, and country picker rows without pulling a full phone-number engine.
npm
npm install e164-compactpnpm
pnpm add e164-compactYarn
yarn add e164-compactUntil published, link from a monorepo sibling:
"e164-compact": "file:../e164-compact"import {
normalizeE164,
tryNormalizeE164,
isNationalLengthValidStrict,
} from "e164-compact";
// Lenient (UX): always returns a string starting with +
const stored = normalizeE164("00971 50 123 4567");
// Strict (APIs): ok / error
const strict = tryNormalizeE164("00971 50 123 4567");
if (strict.ok && isNationalLengthValidStrict(strict.value)) {
// persist strict.value
}import { tryNormalizeE164, isNationalLengthValidStrict } from "e164-compact";
export function assertStorageE164(raw: string): string {
const n = tryNormalizeE164(raw);
if (!n.ok) throw new Error(n.error);
if (!isNationalLengthValidStrict(n.value)) {
throw new Error("National number length out of range for this country code");
}
return n.value;
}Wire this into your own form or API layer however you prefer.
Published tarball includes dist/ (ESM + CJS + types) and NOTICE. There is no separate runtime dependency tree. Measure unpacked size under node_modules/e164-compact/dist after install if you need exact bytes.
| Export | Description |
|---|---|
normalizeE164(input) |
Lenient storage form; strips leading national zero after CC. If no known calling code matches, returns + + stripped digits. |
tryNormalizeE164(input) |
Strict: ok / error — fails on unknown calling code or empty national after strip. |
parseE164Parts(value) |
{ countryCallingCode, nationalNumber }. Lenient: non-+ or unknown prefix uses fallback 971. |
tryParseE164Parts(value) |
Strict: requires +, known CC, non-empty national. |
buildE164(cc, nationalDigits) |
Build +cc + national. |
isE164Syntax(value) |
+ + 1…15 digits, first digit after + is 1–9. |
isNationalLengthValid(value) |
National length vs bounds (lenient parse). |
isNationalLengthValidStrict(value) |
Same with strict parse. |
getNationalLengthBounds(cc) |
{ min, max } for form messages. |
formatE164ForDisplay(value, opts?) |
Spacing for display only. |
filterSupportedCountries(countries, query) |
Match code, label, or cca2. |
localizeSupportedCountryLabels(countries, byCca2) |
Set label from cca2 → name map. |
withLocalePickerLabels(countries, map) |
Alias of localizeSupportedCountryLabels. |
withArabicPickerLabels(countries) |
Applies bundled Arabic map. |
SUPPORTED_COUNTRIES |
{ code, label, cca2 }[] — default English label. |
COUNTRY_LABELS_BY_LOCALE |
ar, fr, es, de, pt, ur, hi, tr, ru → partial cca2 maps. |
COUNTRY_LABELS_AR, …_FR, …_ES, … |
Individual partial maps (same as values in COUNTRY_LABELS_BY_LOCALE). |
CALLING_CODE_PREFIXES |
206 unique CC digit prefixes, longest first. |
NATIONAL_LENGTH_BOUNDS |
Embedded coarse ranges merged with MANUAL_NATIONAL_LENGTH_OVERRIDES. |
MANUAL_NATIONAL_LENGTH_OVERRIDES |
Stricter overrides where you need them (e.g. GCC). |
DEFAULT_NATIONAL_LENGTH_BOUNDS |
Fallback { min: 7, max: 12 }. |
- English is the default on
SUPPORTED_COUNTRIES[].label. - Other languages are partial: some territories may be missing in a given map; missing keys keep the English row unchanged.
- Hindi (
hi) may be sparse in the bundled map; supply your own map vialocalizeSupportedCountryLabelsif needed.
Example:
import {
SUPPORTED_COUNTRIES,
withLocalePickerLabels,
COUNTRY_LABELS_BY_LOCALE,
} from "e164-compact";
const frRows = withLocalePickerLabels(
SUPPORTED_COUNTRIES,
COUNTRY_LABELS_BY_LOCALE.fr as Record<string, string>,
);parseE164Parts/normalizeE164favor forgiving form UX.tryParseE164Parts/tryNormalizeE164suit APIs and validation where silent guessing is undesirable.
tryNormalizeE164fails on valid-looking numbers — The library only accepts known ITU-style calling-code prefixes from embedded data. Updatesrc/data/itu-calling-data.tsif a prefix is missing.isNationalLengthValidStrictis false — Length tables are coarse; tunesrc/manual-national-overrides.tsorsrc/data/national-length-bounds.tsfor your region.- Wrong country after paste — Lenient APIs may infer CC from digits; use strict APIs for unambiguous validation.
All dialing prefixes, picker rows, length tables, and locale maps live under src/data/ as normal source files. Updates are done by editing those modules and opening a PR (see CONTRIBUTING.md). Hand-tuned national length overrides remain in src/manual-national-overrides.ts.
See CHANGELOG.md.
MIT. See NOTICE for third-party data attribution required by upstream licenses.