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

Select Country Code Laravel Package

tapp/select-country-code

A Laravel package for adding a country code selector to forms. It ships country and dial code data with a ready-to-use select component, making it easy to build searchable phone-number inputs in Blade views and Livewire components. Lightweight and simple to drop into any Laravel project.

View on GitHub
Deep Wiki
Context7

Getting Started

Before installing anything, check your Nova version. This package's last release was 2021-03-26, which puts it in the Nova 3 / Vue 2 era. If you're on Nova 4 or 5, assume the compiled field component will not render until proven otherwise — run the install on a throwaway branch first.

composer require tapp/select-country-code

The package is tiny and has no dependents, so treat the source as the documentation:

  1. Open vendor/tapp/select-country-code/composer.json and confirm the actual PSR-4 namespace (e.g. Tapp\SelectCountryCode\) and the service provider.
  2. Read src/ — there are usually only one or two classes: the Nova Field subclass and possibly a config/options source.
  3. Check dist/ for prebuilt JS. If it's absent or stale, you'll need to run npm install && npm run prod inside the vendor directory (or fork it).
  4. If a config file ships, publish it: php artisan vendor:publish --provider="Tapp\..." and inspect the country list it exposes.

First use case — a country code column on an address or user profile:

use Tapp\SelectCountryCode\SelectCountryCode; // verify from composer.json

public function fields(Request $request)
{
    return [
        SelectCountryCode::make('Country Code')
            ->rules('required', 'size:2')
            ->default('US'),
    ];
}

Pair it with a migration that stores the code compactly:

$table->char('country_code', 2)->nullable()->index();

Decide up front whether the field stores ISO 3166-1 alpha-2 (US, GB) or a dial code (+1, +44). The two are not interchangeable, and several countries share a dial code. Inspect the option values in the select before writing the migration.

Implementation Patterns

Keep the field dumb, validate on the server. The dropdown is a UI convenience, not a constraint. Add an explicit rule so a crafted request can't store junk:

use Illuminate\Validation\Rule;

SelectCountryCode::make('Country Code')
    ->rules([
        'required',
        Rule::in(array_keys(config('countries'))), // or the package's own list
    ])
    ->required()
    ->hideFromIndex(),

Display names, store codes. Nova will render the raw code (US) in index/detail views. Resolve it to a human-readable name with league/iso3166 or symfony/intl rather than duplicating a country map:

SelectCountryCode::make('Country Code')
    ->displayUsing(fn ($value) => $value
        ? (new \League\ISO3166\ISO3166)->alpha2($value)['name']
        : '—')
    ->onlyOnForms(),

Text::make('Country', fn () => $this->country_code
    ? (new \League\ISO3166\ISO3166)->alpha2($this->country_code)['name']
    : '—'
)->onlyOnIndex(),

Compose with a phone field. The most common real-world pattern is a two-column pair: country code + national number. Store them separately and concatenate at the boundary (SMS, exports, API responses) through an accessor so you never rebuild the logic in three places:

// app/Models/User.php
public function getE164PhoneAttribute(): ?string
{
    return $this->phone
        ? '+' . ltrim($this->dial_code, '+') . ltrim($this->phone, '0')
        : null;
}

If you need E.164 specifically, prefer a library such as giggsey/libphonenumber-for-php for parsing/formatting rather than string concatenation.

Seeders, imports and API payloads. Normalize incoming codes to uppercase alpha-2 at the model boundary (mutator or form request prepareForValidation), otherwise us, US and U.S. all end up in the column and every where('country_code', 'US') silently misses.

Filtering. For Nova index filters, whereIn on the stored column is enough; you don't need the field for filtering:

public function apply(Request $request, $query, $value)
{
    return $query->where('country_code', $value);
}

Reuse outside Nova. If the package exposes its country array via config or a static method, pull it into your own config/countries.php and use the same list for API validation, CSV import mapping, and Blade forms. If it doesn't expose anything, that's your signal to copy the list out and decouple.

Wrap it. Because maintenance is a risk, don't reference the vendor class in 30 resources. Create one App\Nova\Fields\CountryCode extends SelectCountryCode (or a static factory) so a future swap to Nova's built-in Select is a one-file change:

namespace App\Nova\Fields;

class CountryCode extends \Tapp\SelectCountryCode\SelectCountryCode
{
    public function __construct($name, $attribute = null, $resolveCallback = null)
    {
        parent::__construct($name, $attribute ?? 'country_code', $resolveCallback);
        $this->rules('required', 'size:2');
        $this->default('US');
    }
}

Gotchas and Tips

Compatibility is the biggest gotcha. A 2021 release predates Nova 4's Vue 3 rewrite. Symptoms of a mismatch: the field renders as a plain text input, the select is empty, or the browser console throws a Vue component registration error. Check the Nova JS console and the network response for the field's options before debugging your own code.

Compiled assets vs. source. If the select shows no options, verify the JSON payload first (Nova field metadata), then the rendering. If metadata is populated but the UI is blank, it's an asset problem — run php artisan nova:publish, clear public/vendor, and check the package's dist/ folder is actually present in vendor/.

Missing npm run prod is common in low-traffic packages. If dist/ is empty, the package expects you to build it. That's a strong argument for forking the repo into your own VCS and committing the built assets, rather than depending on a Packagist tarball forever.

Dial code vs. ISO code confusion. +1 covers US, CA, and a dozen Caribbean nations. If the package's option values are dial codes, you cannot derive a country from them — store both, or store only the ISO code and resolve the dial code with libphonenumber.

Don't trust the option list as validation. Whether the list is hardcoded, config-driven, or fetched, always validate server-side with Rule::in against the same source.

Column type and indexing. char(2) (or varchar(2)) with an index is right for alpha-2. Avoid enum — country lists change (Kosovo, newer ISO assignments) and altering the enum is a migration trap. If you store dial codes, use varchar(6) to accommodate +1-684-style values.

Null vs. empty string. Nova selects often submit "" for "no selection". Add a mutator to coerce to null, or nullable() plus 'nullable' in rules, otherwise whereNull('country_code') queries break.

Extension points are thin. With no dependents and 5 stars, expect no published contracts, no events, and no tests. Realistic options: (a) subclass and override the options source, (b) publish/copy the config and stop using the field's internals, or (c) swap to Nova's built-in Select:

Select::make('Country Code')
    ->options(collect((new \League\ISO3166\ISO3166)->all())
        ->mapWithKeys(fn ($c) => [$c['alpha2'] => $c['name']])
        ->sort()
        ->all())
    ->searchable()
    ->rules('required', 'size:2'),

That three-line replacement covers roughly 90% of what this package does and removes the maintenance question entirely. Evaluate honestly whether the field earns its keep before wiring it into many resources.

Debugging checklist. composer show tapp/select-country-code (installed version and requirements) → vendor/tapp/select-country-code/ (namespace, service provider, dist/) → Nova field metadata in the browser network tab → storage/logs/laravel.log for provider boot errors → php artisan nova:field sanity check with a built-in field to isolate whether the issue is the package or your resource.

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource