tapp/filament-country-code-field
A country code select form field, table column, and table filter for Laravel Filament. Easily add searchable country codes to your resources' forms and tables, with a publishable config file. Supports Filament 4.x and 5.x.
What the package is. tapp/filament-country-code-field is a narrow, presentation-layer Laravel package that registers three Filament building blocks — a form select (CountryCodeSelect), a table column (CountryCodeColumn), and a table filter (CountryCodeSelectFilter) — for a single scalar attribute (a country code). It ships a publishable config file and a CSS asset, and otherwise delegates behaviour to Filament's own field/column/filter base classes. There is no service layer, no persistence layer, no migrations, and no domain logic beyond enumerating countries.
Architecture fit. Fit is high if and only if the consuming application is already a Filament panel app on a supported major. The package is additive and orthogonal: it does not touch routing, auth, models, or the database, so it cannot perturb existing domain boundaries. It is a textbook "thin UI package" — roughly 200–400 LOC of real logic plus a country list. For a non-Filament Laravel app, or a Livewire/Tall-stack app without Filament, fit is zero; the field types are unusable outside the Filament form/table lifecycle.
Integration feasibility. Very high. Composer install + optional config publish + three use statements in a Resource. No queue, no scheduler, no external API, no credentials, no migration. A competent Laravel engineer can wire it into one resource in under an hour and validate it in a review environment the same day. The real effort is not integration but the decision around data representation (see below).
Technical risk. Low blast radius, non-trivial longevity risk.
| Risk | Severity | Notes |
|---|---|---|
| Data representation ambiguity | High | README never states whether the field stores ISO 3166-1 alpha-2 (US), alpha-3 (USA), or a dial code (+1). This determines whether the value is interoperable with phone validation, address, tax, and shipping logic downstream. Must be confirmed from source before schema commitment. |
| Longevity / bus factor | Medium | 21 stars, 0 dependents, one primary maintainer plus a small contributor pool. Effectively single-vendor stewardship. |
| Filament major coupling | Medium | v2.x targets Filament 4.x/5.x; v1.x targets Filament 3.x. Filament 5 support only landed in v2.0.2, so that combination is young. A Filament 6 major will require a package major. |
| PHP floor shift | Medium | v2.1.0 dropped PHP 8.2 and added 8.5. Teams still on 8.2 are pinned to ≤2.0.2, which lacks the CSS path fix. |
| Asset registration fragility | Low–Medium | The most recent patch (v2.1.1) was purely a CSS path registration fix — evidence that asset publishing is the historically brittle surface. |
| Security / supply chain | Low | No network calls, no eval, no dynamic code loading. Dependabot is active and CI runs tests plus Pint, which is a positive hygiene signal. |
Key questions to resolve before commitment.
+ prefix, nullability)?league/iso3166 / ICU? How stale can it get (e.g., new ISO codes, Kosovo, disputed territories)?pt_BR was added over the project's life. What is the baseline locale set, and are country names translated or only the chrome?Build-vs-buy note. A TPM should price the alternative honestly: an internal Filament field wrapping a country enum is roughly 1–2 engineer-days, and it removes the external dependency entirely. With 21 stars and zero dependents there is no ecosystem signal that this package is load-bearing for anyone else, so adopting it is a convenience decision, not a de-risking decision. The correct framing is "buy a day of engineering time for a small stewardship liability," which is usually the right trade for a leaf-level UI widget — provided the encoding question resolves cleanly.
Stack fit. Required baseline for current 2.x: PHP ≥ 8.3 (post-2.1.0), Laravel with Filament 4.x or 5.x, Composer 2. Filament 5 consumers must pin ^2.0.2 at minimum — 2.0.0/2.0.1 are Filament-4-only in practice. Filament 3 consumers must stay on the 1.x line and its separate documentation branch, which means the two lines are not interchangeable and should not coexist across a multi-panel monorepo without care.
Installation and configuration.
composer require tapp/filament-country-code-field:"^2.1"
php artisan vendor:publish --tag="filament-country-code-field-config"
Pin a caret on ^2.1 rather than a floating ^2.0 so you inherit the CSS path fix and PHP 8.5 support. Publishing the config is a deliberate choice: published config becomes your artifact and your upgrade liability; publish only if you actually need to override locale, ordering, or the country subset. If defaults suffice, skip the publish step and keep upgrades trivial. Commit the lockfile entry and verify the CSS asset registers correctly in the built panel — that is the one thing that has broken in production history.
Migration path.
1.x → 2.x jump is a package major tied to a Filament major. Schedule it with the Filament upgrade, not separately. The 1.x docs branch remains available for reference during the transition.select country columns: no data migration is required if the package stores the same encoding you already store. If it does not — the common case, where legacy rows hold dial codes or full country names — you need an explicit backfill with an idempotent mapping table and a rollback plan. Do not discover this in staging.league/iso3166 or symfony/intl usage: confirm the package's country list does not diverge from your validation layer, or you will create rows the validator rejects.Compatibility and sequencing.
CountryCodeSelect into one secondary resource. Read the field's dehydrateStateUsing/formatStateUsing to answer the encoding question definitively. Write the answer into the team's data dictionary.vite dev.app/Filament/ and confirm the app still runs. If that is true, the dependency is reversible and the risk is bounded. If it is false, you have hidden coupling.Maintenance. Ongoing cost is close to zero in steady state — no runtime services, no data to reconcile, no cron. The cost concentrates in upgrade windows: every Filament major triggers a package major, and every PHP floor shift can force a pin (the drop of PHP 8.2 in v2.1.0 is the concrete precedent). Budget roughly half a day per Filament major plus a quarterly 15-minute check of the changelog. Because the package is small and permissively licensed, the credible worst case is a fork-and-vendor, which is a few hours rather than a few days — this should be stated explicitly in the risk register so the small maintainer base does not get over-weighted.
Support. There is no vendor SLA. Support is community/best-effort via GitHub issues, with one primary maintainer and an active Dependabot-driven maintenance loop. Treat issues as "we fix or fork" rather than "vendor responds." Internal ownership must be assigned to a named engineer on the platform team; an unowned third-party Filament widget is the classic orphan dependency. Localisation support is thin and contribution-driven (only pt_BR landed historically), so any locale beyond the defaults should be assumed to be internal work.
Scaling. No scaling dimension of consequence. The country list is a static in-process array; render cost is a select with roughly 250 options, which is negligible at any realistic admin-panel concurrency. If the list becomes searchable/AJAX-driven in a future version, re-evaluate, but the current shape is a non-issue. The filter translates to a simple where on a low-cardinality string column — index it if the table is large, but that is a database concern, not a package concern.
Failure modes to monitor.
Ramp-up. Effectively nil. The README is complete for the three usage paths, screenshots exist for field and column/filter, and version compatibility is documented in a table — better than most packages at this size. A new engineer can use the components correctly from the README alone; the only knowledge that must be transferred verbally is the encoding contract and the fact that this is a leaf dependency eligible for vendoring. Onboarding cost: under an hour, plus the 30-minute exit rehearsal.
Recommendation. Adopt, conditional on resolving the encoding question and confirming the Filament/PHP matrix matches the target application. Scope it as a convenience dependency on a small number of resources first, assign internal ownership, add the two regression tests, and pre-agree the fork contingency. Do not let it spread to dozens of resources before the encoding contract is documented — the package itself is low-risk, but a silently inconsistent country-code column across a schema is not.
How can I help you explore Laravel packages today?