Installation
composer require dotmarn/laravel-tel-input
npm install intl-tel-input --save
Add the package's JS to your layout (e.g., resources/js/app.js):
import 'intl-tel-input/build/js/intlTelInput';
import 'laravel-tel-input/dist/js/laravel-tel-input';
Publish Assets
npm run dev # or `npm run build` for production
First Blade Usage
@telInput(['name' => 'phone', 'defaultCountry' => 'us'])
Render a phone input field with auto-formatting and country dropdown:
<form method="POST" action="/contact">
@telInput(['name' => 'phone', 'required' => true])
<button type="submit">Submit</button>
</form>
Basic Workflow
Form Handling
@telInput([
'name' => 'user_phone',
'defaultCountry' => 'auto', // or 'gb', 'us', etc.
'separateDialCode' => true,
'onlyCountries' => ['us', 'ca', 'gb']
])
phone rule (e.g., Rule::phone()) with the submitted phone and phone-country fields.Dynamic Defaults
@telInput([
'name' => 'phone',
'defaultCountry' => $user->country_code ?? 'us'
])
Livewire 2/3
use Dotmarn\TelInput\Livewire\TelInput;
public function mount() {
$this->telInput = new TelInput([
'name' => 'phone',
'defaultCountry' => 'auto',
]);
}
<livewire:your-component>
@telInput($telInput)
</livewire:your-component>
public function updated($property) {
$this->validate([
'phone' => 'required|phone',
'phone-country' => 'required|string',
]);
}
Country Sync
@telInput([
'name' => 'phone',
'syncCountry' => true, // Syncs country dropdown with another field
'syncCountryField' => 'country_code'
])
Custom Styling Override the default CSS by publishing the package’s assets:
php artisan vendor:publish --tag=laravel-tel-input-assets
Then extend the published tel-input.css.
Server-Side Logic
libphonenumber (e.g., giggsey/LibPhonenumber-for-PHP) to parse and validate phone numbers:
use libphonenumber\PhoneNumberUtil;
use libphonenumber\PhoneNumberFormat;
$phoneUtil = PhoneNumberUtil::getInstance();
$phone = $phoneUtil->parse($request->phone, $request->{'phone-country'});
$e164 = $phoneUtil->format($phone, PhoneNumberFormat::E164);
Missing JS Dependencies
intlTelInput is not defined.intl-tel-input and laravel-tel-input JS are imported after jQuery (required by intl-tel-input).
// resources/js/app.js
import $ from 'jquery';
import 'intl-tel-input/build/js/intlTelInput';
import 'laravel-tel-input/dist/js/laravel-tel-input';
Livewire Data Binding
wire:model alongside @telInput:
@telInput([
'name' => 'phone',
'wire:model' => 'phone'
])
public $phone;
public $phone_country;
Validation Mismatches
phone and phone-country fields don’t match the expected format.$this->validate([
'phone' => 'required|string',
'phone-country' => 'required|string|in:'.implode(',', ['us', 'ca', 'gb']),
]);
giggsey/LibPhonenumber-for-PHP for robust validation:
$phoneUtil = PhoneNumberUtil::getInstance();
try {
$phone = $phoneUtil->parse($request->phone, $request->{'phone-country'});
$isValid = $phoneUtil->isValidNumber($phone);
} catch (\Exception $e) {
$isValid = false;
}
Check Console Logs
F12) and check for errors like:
Uncaught TypeError: intlTelInput is not a function.404 for missing JS/CSS files (verify npm run dev was executed).Inspect Hidden Fields
phone-country and phone-number. Verify they exist in the DOM:
<input type="hidden" name="phone-country" id="phone-country">
<input type="hidden" name="phone-number" id="phone-number">
Country Code Conflicts
defaultCountry is set to an unsupported code (e.g., 'uk' instead of 'gb'), the dropdown may not load correctly. Use ISO 3166-1 alpha-2 codes.Custom Country Lists
php artisan vendor:publish --tag=laravel-tel-input-config
config/laravel-tel-input.php:
'countries' => ['us', 'ca', 'mx', 'gb'], // Custom list
Dynamic Country Loading
@telInput([
'name' => 'phone',
'countries' => $dynamicCountries, // Array of country codes
])
Localization
intl-tel-input. Add language files to your project and configure:
// In your JS initialization
window.intlTelInputGlobals.locales['es'] = {
// Spanish translations
};
@telInput(['name' => 'phone', 'language' => 'es'])
Event Listeners
countrychange or input events via JavaScript:
document.addEventListener('DOMContentLoaded', function() {
const input = document.querySelector('#phone');
input.addEventListener('countrychange', function(e) {
console.log('Country changed:', e.countryData.iso2);
});
});
How can I help you explore Laravel packages today?