bissolli/nova-phone-field
A Laravel Nova phone field that renders an international telephone input with country flag selector, automatic formatting, and validation. Stores numbers in E.164 and drops into Nova resources with minimal setup.
Architecture fit: This is a single Laravel Nova form field that renders a phone input whose mask adapts to the country code the operator types. Architecturally it is a UI widget, not a data layer. It does not validate server-side, does not normalize to E.164, and does not own the canonical phone value — despite description language implying "built-in validation" and "consistent storage." That constrains its role to operator data entry inside an admin panel, where it must sit alongside a real validation/normalization step, never instead of one. Two legitimate uses: (1) a low-cost polish item in a legacy Nova 2 / Laravel 6 estate, and (2) a forkable, MIT-licensed reference implementation for a custom field we build ourselves.
Integration feasibility: Low to moderate, and the release history does not improve it. v0.0.4 is a one-line bump adding Laravel 6.0 support — that is the compatibility ceiling, not a revival. By implication the package targets Nova 2.x APIs and ships compiled Vue assets from the Nova 2/3 era. On a modern stack (Laravel 7+, Nova 4/5 with Vue 3) Composer may refuse to resolve, and forcing it with --ignore-platform-reqs buys a field that mounts but silently never binds its mask. Integration itself is genuinely one line — composer require, then PhoneNumber::make('Phone') in a resource — with no migrations, no config publish, no service provider work. The effort is not in wiring it up; it is in proving it works on our exact Nova version and owning it afterwards.
Technical risk: Concentrated and asymmetric — cheap to try, expensive to depend on. Specific risks a TPM should record:
resources/js/, with no config file. "Supports international numbers" quietly means "supports the countries someone enumerated in 2019." Adding a region means editing vendor code.Key questions to answer before any commitment:
composer require resolve cleanly without --ignore-platform-reqs?Stack fit: Narrow. Fits Laravel 6 / Nova 2.x back-office CRUD screens — leads, customers, support tickets — where the operator benefits from formatted input. Does not fit Nova 4/5, does not fit customer-facing or compliance-sensitive phone capture, and does not fit any flow where the phone number is a system-of-record identifier without additional server-side controls.
Migration path: There is no migration — the package stores nothing and adds no schema. The real migration path is away from it. The realistic alternatives, in ascending order of cost:
Text field plus a FormRequest rule using propaganistas/laravel-phone — cheapest, no masking UX.intl-tel-input or a maintained phone library — marginally more upfront, far less over three years, no framework pin.If we proceed, isolate it behind a single resource helper (protected function phoneField(...)) so the swap is one file, not N resources.
Compatibility: Treat v0.0.4 as the ceiling. Verify Nova major version against the compiled assets before planning anything. Pin the Composer version explicitly. Plan the next Nova upgrade as the fork trigger, and document that expectation now rather than discovering it mid-sprint.
Sequencing:
propaganistas/laravel-phone or giggsey/libphonenumber-for-php) and E.164 normalization via fillUsing() or a model mutator — this ships in the same PR as the field, not after.Maintenance: Effectively unmaintained upstream. One release in the package's history (a Laravel 6 compatibility bump, September 2019), no tests, no config, no issue triage. Any fix — new country region, styling, Nova compatibility, JS dependency patch — lands in our fork. Budget that as ongoing ownership, not a one-time integration cost. The mitigation is isolation: one helper method, one fork point, documented.
Support: No vendor path. Internally, the field needs a named owner and a documented debug checklist: confirm autoload, verify Nova version against assets, check console for mask-library errors, check the network tab for the field's JS, inspect resources/js/ to confirm the tested country code is even in the map. Without an owner this becomes unowned liability, not a decision.
Scaling: Trivially scalable at runtime — client-side masking adds no backend load and no storage. It scales badly in breadth: every new country, locale, or Nova version is manual work in vendor code. If the product roadmap includes international expansion or a Nova upgrade, this package becomes a blocker rather than a convenience, and the replacement effort grows with the number of resources that reference it.
Failure modes to plan for:
+ or +5 alone produces a temporarily nonsensical pattern; mitigate with ->placeholder() and ->default('+55 ').resources/js/.Ramp-up: Near-zero for engineers already fluent in Nova — the API is Text plus ordinary setters (->rules(), ->placeholder(), ->nullable(), ->fillUsing()). A new engineer can ship a field in under an hour. The non-obvious learning is the debugging path for silent JS failure and the discipline of asserting on normalized values, not masked strings, in tests.
Recommendation: Approve a short engineering spike, not a commitment. Adopt only if it binds cleanly on our exact Nova version, server-side validation and E.164 normalization ship alongside it, and we formally accept ownership with a named maintainer and a fork trigger. Otherwise build the thin custom field over a maintained phone library — marginally more upfront, materially less risk across a three-year horizon.
How can I help you explore Laravel packages today?