Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Country Field Laravel Package

parfaitementweb/filament-country-field

A Filament form field for selecting countries. Adds a searchable country dropdown with flags, ISO codes, and localized names to your admin panels, making it quick and consistent to capture country data in Filament resources and forms.

View on GitHub
Deep Wiki
Context7

Getting Started

The release that matters here is 2.5.6's Laravel 13 support (PR #46). Everything else in this tag is Dependabot churn on GitHub Actions (actions/checkout, ramsey/composer-install, dependabot/fetch-metadata) and has zero runtime impact. Concretely: the package widened its illuminate/* / laravel/framework constraint to include 13.x. No PHP API changed, no Filament API changed, no deprecations. If you're on Laravel 10–12 today, this release is a no-op for you; if you're planning a Laravel 13 upgrade, this package is no longer a blocker.

First steps:

composer require parfaitementweb/filament-country-field
php artisan filament:assets          # or: vendor:publish --tag="filament-country-field-assets"

The second command is the one people forget. The field renders flags as bundled SVGs; without the asset publish step you get a working select with broken/empty flag tiles in production while everything looks fine locally (dev server often resolves the vendor path).

First use case — a single country column:

use Parfaitementweb\FilamentCountryField\Forms\Components\CountryField;

CountryField::make('country')
    ->searchable()
    ->required();

The state is the ISO 3166-1 alpha-2 code (BE, FR, US) — not the country name. So your migration should be $table->string('country', 2)->nullable(); and nothing else. Open the field class itself first (src/Forms/Components/CountryField.php) to see the fluent surface; it extends Filament's Select, so everything you know about Select (->live(), ->afterStateUpdated(), ->placeholder(), ->disabled()) applies, plus the country-specific helpers.

Implementation Patterns

Restrict the list rather than validating afterwards. For a Benelux-only signup form:

CountryField::make('country')
    ->countries(['BE', 'NL', 'LU'])
    ->searchable()
    ->required(),

->exclude([...]) is the inverse and reads better when you're removing a handful from the full set. Doing it at the field level means the browser can't submit an out-of-scope code at all — cheaper than a Rule::in() in a FormRequest, though add the rule anyway if the endpoint is reachable outside Filament.

Address forms: pair the field with the phone prefix. ->withPhonePrefix() renders the dialling code alongside the country, which is exactly what you want in a checkout form where the user picks country and the phone input's prefix updates live:

CountryField::make('country')
    ->withPhonePrefix()
    ->live()
    ->afterStateUpdated(fn (Set $set, ?string $state) =>
        $set('phone_prefix', Country::phonePrefix($state))
    ),

Table columns. Keep the raw code in the DB and translate at render time — never store the display name, because names are localized and change (see Eswatini/Türkiye). A TextColumn with ->formatStateUsing() and ->badge() is the low-friction path; use ->withEmojiFlags() in the form and a small code→emoji map in the column so the two views agree.

Enum casting. If you already have a Country enum (or ARCHTECH/-style package), ->castStateUsing() on the field and a casts() entry on the model keep the code out of your domain layer:

protected function casts(): array
{
    return ['country' => CountryCode::class];
}

This is the pattern I'd reach for on anything larger than a single form — it makes $order->country->phonePrefix() available everywhere instead of re-deriving from a string.

Livewire reactivity chains. ->live() plus ->afterStateUpdated() is how you drive dependent selects (state/province lists, currency, tax rate, shipping zone). Watch the round-trip count: chaining three live fields in a wizard step fires three requests per keystroke on the search input unless you use ->live(debounce: 500) or move the chain into a ->live(onBlur: true) equivalent.

Gotchas and Tips

  • Assets, again. The single most common "it's broken" report with this package is unpublished flag assets. Run php artisan filament:assets in your deploy script, after config:cache invalidation, and check that public/ (or your asset disk) actually receives the SVGs. php artisan optimize:clear is the debugging first move.
  • Emoji flags are not portable. ->withEmojiFlags() looks great on macOS/iOS and renders as bare letter pairs on Windows and many Linux Chrome builds. If flag accuracy matters, ship the SVGs.
  • Store 2 characters, be consistent. Mixing alpha-2 (BE) and alpha-3 (BEL) across tables is the classic migration regret; the package gives you alpha-2 from the field, so pick that as the house standard and write it into your schema docs.
  • Uppercase, always. The state comes back uppercase. If you seed data by hand or import CSVs, normalize with strtoupper() before comparing — SQLite and MySQL collation differences will bite you in tests but not in production.
  • Filament v3 vs v4. The component namespace is Parfaitementweb\FilamentCountryField\Forms\Components\CountryField; the class extends Filament\Forms\Components\Select, so a Filament major bump can change inherited behaviour (search debounce, option rendering) without the package's own changelog mentioning it. Pin Filament in composer.json and read the package's composer.json constraints on upgrade day.
  • Laravel 13 note. 2.5.6 is the release that lets you sit on Laravel 13. It's a constraint widening only — but if you maintain a fork or a downstream package that requires this one, you'll want ^2.5.6 rather than ^2.5 with a tight Laravel pin, otherwise Composer resolves to an older tag and you'll spend an hour wondering why the upgrade fails.
  • Testing. Use Filament's form testing helpers (assertFormSet, fillForm(['country' => 'BE'])) rather than asserting on rendered HTML; the option list is long and the markup includes search chrome that changes between Filament minors. For validation, assert that an out-of-whitelist code like 'ZZ' fails — a test that catches an accidentally-removed ->countries() call.
  • Extension point. If you need country data outside the form (reporting, exports, API resources), don't scrape the field's option list — it's a UI concern. Reach for the underlying ISO data source directly and use the field purely for input.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast