@finofo/react-international-phone
v4.9.0
Published
☎️ International phone input component for React
Readme
@finofo/react-international-phone
This is Finofo's fork of
ybrusentsov/react-international-phone(the upstream account was renamed fromgoveo; older notes here still say goveo). Published to npm as@finofo/react-international-phone. The original package is still actively maintained upstream; this fork exists for dependency control, publishing independence, and consumer-coupled patching for our own applications.
🤙 International phone input component for React
The badge tracks what's published. It can legitimately lag
package.jsononmain— publishing is manual (workflow_dispatch), so merging never ships. A gap means "not published yet", not "broken".

Why the fork exists
The upstream react-international-phone package is maintained by Yurii Brusentsov and is an excellent component. We forked it because:
- Dependency staleness. Upstream
v4.4.0shipped with[email protected],[email protected],[email protected],jest@29, an 18-month-old lockfile, and a long tail of open Dependabot CVE alerts on devDependencies. We needed a current, auditable dependency surface without waiting on upstream's release cadence. The fork is now on[email protected],eslint@10(flat config),storybook@10(with@storybook/addon-vitest),jest@30,stylelint@17,tsup@8, and actively clears CVE alerts via pnpm overrides where upstream hasn't yet. SeeCHANGELOG.finofo.mdfor the per-version devDep delta. - Publishing independence. Upstream publishes via
semantic-releasetriggered by push-to-master, tied to their npm account. We wanted a manual, OIDC-gated publish workflow tied to Finofo's npm account so we can cut releases on our own timeline. - Consumer coupling. This package is consumed by an internal Finofo application. Owning the fork lets us backport fixes and coordinate breaking changes with that consumer the same day, rather than round-tripping through upstream PR review.
Upstream is not abandoned. We pull from them regularly (see CHANGELOG.finofo.md for sync history). The fork is a thin layer on top, not a divergent rewrite.
The public API surface is identical to upstream — same exports, same types, same CSS class names. We don't add or remove exports without upstream doing so first.
Formatting behavior diverged in 4.9.0. 142 countries that upstream renders as bare digits now get a formatting mask here (see below). Same inputs, same API, different display grouping for those countries. If you need output byte-identical to upstream, that's the one thing to know about.
Fork timeline
- Forked at: upstream
v4.4.0, commit1a7a040. First Finofo publish:@finofo/[email protected]. - Package scope changed to
@finofo/…so both packages can coexist in an npm install if needed and npm can clearly distinguish the fork. - Subsequent syncs are recorded in
CHANGELOG.finofo.md. Most recent upstream sync: upstreamv4.8.0→@finofo/[email protected], picking up country-data updates (AR / BR / UAE / GCC / French DOM-TOM), theallowMaskOverflowprop, andReact.memoperf work onCountrySelector. 4.8.2(2026-04-18) was a pure devDep + tooling sweep with zero source changes and zero runtime-affecting dist changes. Brought eslint, stylelint, jest, storybook, tsup, sass, and postcss to current majors; migrated eslint to flat config; cleared 8 of 10 open CVE alerts by removing unused tooling (semantic-release,@storybook/preset-scss) and addingpnpm.overridesfor residual ReDoS transitives; added a post-build bundle-size regression guard.- Latest fork release:
4.9.0(2026-07-29), the country-mask release and the first fork version whose output differs from upstream. 142 of the 143 countries that previously rendered as bare digits gained a formatting mask — only Kiribati still has none, because libphonenumber publishes no derivable format for it. Includes four genuine bug fixes, notably Argentine international-mobile numbers losing their 11th digit (upstream #197, unfixed there) and a Canadian area-code typo that made+1 367numbers guess as US. Ships with a real-number audit pipeline that gates CI. SeeCHANGELOG.finofo.mdfor the full breakdown. - Dependency modernization is ongoing in parallel to feature syncs. See
CLAUDE.mdfor the current state of dependency groups, ignore rules, and the reasoning.
What's different from upstream
Mostly operational, plus one behavioral difference in country formatting since 4.9.0:
| Axis | Upstream | Finofo fork |
| --------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------- |
| npm package name | react-international-phone | @finofo/react-international-phone |
| Country formatting masks | 143 of 218 countries render bare digits | 1 (Kiribati); the other 142 gained a mask in 4.9.0 |
| Mask correctness gate | none | audit:masks:ci applies every mask to ~2000 real numbers; fails CI on new truncation |
| Default branch | master | main |
| Publish trigger | semantic-release on push to master | Manual workflow_dispatch with OIDC trusted publishing |
| Dependabot groups | default / flat | Restructured around publish-impact; emitter toolchain pinned to consumer |
| Docs site | Vercel-hosted by upstream | packages/docs/ excluded from workspace; upstream continues to host |
| Version scheme | Semver tracking feature releases | {upstream_version} or {upstream_version}.{finofo_patch} to signal fork-level packaging deltas |
| Storybook integration demos | Chakra v1, MUI v5 | Chakra v2, MUI v9, shadcn/ui (Tailwind v3), Ant v6 |
| Test runner | @storybook/test-runner | Migrated to @storybook/addon-vitest (upstream's recommended path) |
| Lint toolchain | .eslintrc (legacy), eslint@7 | eslint.config.mjs (flat config), eslint@10, typescript-eslint@8, stylelint@17 |
| Build-size guard | none | scripts/check-bundle-size.mjs post-build; tsup.config.ts pinned to target: 'es2020' |
| Public API | stable | identical; we never add or remove exports without upstream doing so first |
Features
- 😎 Easy to integrate — Just import and use, no initial setup. Integrate with any UI library via a headless hook.
- 🔍 Country guessing — Start typing and the component guesses the country and applies the format. Flags via Twemoji.
- 🌍 Near-universal formatting — 217 of 218 countries have a formatting mask, audited against real phone numbers rather than only libphonenumber's synthetic examples.
- ✨ Lightweight — Small bundle, no third-party runtime dependencies.
- 🌈 Easy to customize — Props for styles and behavior.
- ⌨ Caret position handling — Typing mid-input, selection, deletion all feel natural.
- ✔️ Validation — Helper functions for validating entered phone numbers.
Installation
$ npm install @finofo/react-international-phone
# or
$ pnpm add @finofo/react-international-phone
# or
$ yarn add @finofo/react-international-phoneBasic usage
import { useState } from 'react';
import { PhoneInput } from '@finofo/react-international-phone';
import '@finofo/react-international-phone/style.css';
const App = () => {
const [phone, setPhone] = useState('');
return (
<div>
<PhoneInput
defaultCountry="ua"
value={phone}
onChange={(phone) => setPhone(phone)}
/>
</div>
);
};Documentation
The upstream official documentation is the API reference. Every prop, hook, and helper documented there behaves identically here. Two differences to keep in mind: the package name in the install examples (@finofo/react-international-phone instead of react-international-phone), and the country formatting masks added in 4.9.0, which upstream doesn't have — so the formatted output shown in their examples for those countries won't match what this fork renders.
Storybook integration demos (Chakra UI v2, Material UI 9, shadcn/ui, Ant Design 6) live under src/stories/UiLibsExample/. Run pnpm storybook to browse them — this fork has no hosted Storybook. Upstream deploys theirs, which is still a fine API reference but renders upstream's formatting, so masked countries will look different there than here.
Migration
Version numbering tracks upstream. Upstream's migration guides apply unchanged:
Fork-specific release notes (dependency bumps, packaging changes, etc. that aren't in upstream) are in CHANGELOG.finofo.md.
Working on the fork
If you're working on the fork (including AI assistants), CLAUDE.md has the operational context: consumer coupling, publish process, tarball-install verification, upstream sync workflow, and the reasoning behind the custom Dependabot setup.
This is an internal Finofo fork; we're not accepting outside contributions. For the upstream project, see ybrusentsov/react-international-phone.
License
MIT. Same as upstream.
