@finofo/react-international-phone
Version:
āļø International phone input component for React
116 lines (81 loc) ⢠8.82 kB
Markdown
# @finofo/react-international-phone
> **This is Finofo's fork of [`goveo/react-international-phone`](https://github.com/goveo/react-international-phone).** 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 Finofo's web app.
š¤ International phone input component for React



[Live demo: Storybook](https://react-international-phone-storybook.vercel.app) (upstream, same behavior)

## Why the fork exists
The upstream `react-international-phone` package is maintained by Yurii Brusentsov and is an excellent component. We forked it because:
1. **Dependency staleness.** Upstream `v4.4.0` shipped with `typescript@4.9.4`, `eslint@7.32.0`, `storybook@7.4.1`, `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 `typescript@5.9.3`, `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. See `CHANGELOG.finofo.md` for the per-version devDep delta.
2. **Publishing independence.** Upstream publishes via `semantic-release` triggered 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.
3. **Consumer coupling.** `@finofo/react-international-phone` is consumed by our flagship product (`finofo-web-app`). Having our own fork lets us backport fixes and coordinate breaking changes with our consumer in 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 and behavior match upstream version-for-version.
### Fork timeline
- **Forked at:** upstream `v4.4.0`, commit [`1a7a040`](https://github.com/goveo/react-international-phone/commit/1a7a040). First Finofo publish: `@finofo/react-international-phone@4.4.0`.
- **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`](./CHANGELOG.finofo.md). Most recent upstream sync: upstream `v4.8.0` ā `@finofo/react-international-phone@4.8.1`, picking up country-data updates (AR / BR / UAE / GCC / French DOM-TOM), the `allowMaskOverflow` prop, and `React.memo` perf work on `CountrySelector`.
- **Latest fork release: `4.8.2`** (2026-04-18) is 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 adding `pnpm.overrides` for residual ReDoS transitives; added a post-build bundle-size regression guard. See `CHANGELOG.finofo.md` for the full per-PR breakdown.
- **Dependency modernization is ongoing** in parallel to feature syncs. See [`CLAUDE.md`](./CLAUDE.md) for the current state of dependency groups, ignore rules, and the reasoning.
### What's different from upstream
At the source level, very little. The differences are operational:
| Axis | Upstream | Finofo fork |
| --------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------- |
| npm package name | `react-international-phone` | `@finofo/react-international-phone` |
| 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](https://twemoji.twitter.com/).
- ⨠**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
```sh
$ npm install @finofo/react-international-phone
# or
$ pnpm add @finofo/react-international-phone
# or
$ yarn add @finofo/react-international-phone
```
## Basic usage
```tsx
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](https://react-international-phone-docs.vercel.app/) is the API reference. It's accurate for this fork version-for-version; only the package name in the install examples differs (`@finofo/react-international-phone` instead of `react-international-phone`).
Storybook integration demos (Chakra UI v2, Material UI 9, shadcn/ui, Ant Design 6) live under `src/stories/UiLibsExample/` and are visible in the storybook dev server (`pnpm storybook`).
## Migration
Version numbering tracks upstream. Upstream's migration guides apply unchanged:
- [Update from v3 to v4](https://react-international-phone-docs.vercel.app/docs/Migrations/migrate-to-v4)
- [Update from v2 to v3](https://react-international-phone-docs.vercel.app/docs/Migrations/migrate-to-v3)
- [Update from v1 to v2](https://react-international-phone-docs.vercel.app/docs/Migrations/migrate-to-v2)
Fork-specific release notes (dependency bumps, packaging changes, etc. that aren't in upstream) are in [`CHANGELOG.finofo.md`](./CHANGELOG.finofo.md).
## Working on the fork
If you're working on the fork (including AI assistants), [`CLAUDE.md`](./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 [`goveo/react-international-phone`](https://github.com/goveo/react-international-phone).
## License
MIT. Same as upstream.