Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Joeseph Chen's avatar

Livewire Telephone Input

Hi, I'm trying to implement this package https://github.com/jackocnr/intl-tel-input using livewire, been trying with no success and searching for a few hours with no luck finding an example of implementing it.

Currently trying to make a telephone input component that has a country selection dropdown and also automatically change the flags based on user ip. And when user submit the form, it will retain the international code, and remove the leading zero if user input the phone number with zero.

here is my current code

@props(['disabled' => false])

<div class="w-full">
	<input x-data="{ value: @entangle($attributes->wire('model')) }"
	       x-ref="input"
	       x-init="intlTelInput($refs.input, {
	          nationalMode: true,
            utilsScript: 'js/utils.js',
            initialCountry: 'id'
				 })"
	       x-on:change="value = window.intlTelInputGlobals.getNumber()"
	       type="tel"
		{{ $disabled ? 'disabled' : '' }}
		{{ $attributes->merge(['class' => 'form-input block w-full sm:text-sm border-gray-200 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500']) }}
	>
</div>

any clue how to implement it?

1 like
13 replies
aurawindsurfing's avatar

Hey @joeseph chen

I use this package for my phone dilemmas: https://github.com/Propaganistas/Laravel-Phone

It also has validation helper so you could validate your phone using it and livewire validation logic.

I'm not too sure if you even need to use alpinejs in that case, you can skip the whole country selection to be honest, just validate like this:

$m->to = PhoneNumber::make($a->user->phone, ['UK', 'DE', 'FR'])->formatE164();

It works quite well for me.

Joeseph Chen's avatar
Joeseph Chen
OP
Best Answer
Level 20

hello @aurawindsurfing thank you for your reply, I tried to look into the package, but it not really what I'am looking for, but the good news is I got it work for the package I mention in my question, and I think the package you mention is quiet good as validation side, I will try to implement it together with the package in my question. Thank you, cheers :D

1 like
XternalSoft's avatar

Hello, you have almost same code as me. My problem : I lose "formatting" of the numbers after change on another field (after livewire refresh). Despite the use of "wire:ignore"

maybe my code can help you ?

<div class="col-span-6 sm:col-span-2" wire:ignore>
    <x-frontoffice.input.tel label="Mobile phone" :required="true" format="vertical"
                             x-data=""
                             x-ref="mobile_number" autocomplete="off"
                             x-init="()=> { myIntlTelInput($refs.mobile_number);}"
                             x-on:change="let number = window.intlTelInputGlobals.getInstance($refs.mobile_number).getNumber(); console.log(number);$dispatch('input',number)"
                             model-name="user.mobile_number"></x-frontoffice.input.tel>
</div>

external JS function is

window.myIntlTelInput = function (input) {
    //Ajout un petit delai pour que livewire ai le temps de mettre la valeur dans le champ
    setTimeout(() => {
        intlTelInput(input, {
            preferredCountries: [],
            initialCountry: "auto",
            utilsScript: "utils.min.js",
            geoIpLookup: function (success, failure) {
                let country = Cookies.get('ipcountry');
                if (country !== undefined) {
                    success(country);
                    return;
                }

                fetchJsonp("ipinfo.io").then(function (response) {
                    return response.json()
                }).then(function (json) {
                    let countryCode = (json && json.country) ? json.country : "us";
                    Cookies.set('ipcountry', countryCode, {expires: 7});
                    success(countryCode);
                }).catch(function (ex) {
                    console.log('parsing failed', ex);
                });

            }
        });
    }, 200);
}

ps: I use "Cookie" for limit call to ipinfo

1 like
XternalSoft's avatar

Ok, i found a solution for my refresh format problem...

In my save function in livewire emit an event

 public function save()
    {
        $this->validate();
        $this->user->save();
        $this->emit('toast', 'success', __('Saved successfully'));
        $this->emit('refreshPhoneFields');
    }

And in Javascript

 @push('scripts')
        <script>
            Livewire.on('refreshPhoneFields', () => {
                let instance = window.intlTelInputGlobals.getInstance(document.getElementById('user.mobile_number'));
                instance.setNumber(instance.getNumber());
                instance = window.intlTelInputGlobals.getInstance(document.getElementById('user.work_number'));
                instance.setNumber(instance.getNumber());
                instance = window.intlTelInputGlobals.getInstance(document.getElementById('user.fixedline_number'));
                instance.setNumber(instance.getNumber());
            })
        </script>
    @endpush
1 like
Joeseph Chen's avatar

I got it to work now, with just a little fix needed. Right now the flag keep changing to initial country detected by ip when I shift the focus from the input even when I input another country code, and another thing is it doesn't automatically put the country code at the start of the input.

Here is my current code


@props(['disabled' => false])

<div class="w-full">
	<input x-data="{ value: @entangle($attributes->wire('model')) }"
	       x-ref="input"
	       x-init="window.intlTelInput($refs.input, {
	          dropdownContainer: document.body,
	          geoIpLookup: function(success, failure) {
							axios.get('https://ipinfo.io?token=token_number')
									.then((response) => {
									  return success((response && response.data.country) ? response.data.country : 'id')
									})
									.catch((error) => {
									  return failure(error)
									})
						},
	          	nationalMode: false,
	          	autoHideDialCode: false,
            	utilsScript: 'js/utils.js',
            	initialCountry: 'auto'
				 })"
	       x-on:change="value = $event.target.value"
	       type="tel"
		{{ $disabled ? 'disabled' : '' }}
		{{ $attributes->merge(['class' => 'form-input block w-full sm:text-sm border-gray-200 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500']) }}
	>
</div>

1 like
Xkill1996's avatar

@Joeseph Chen Can u show me the usage of this blade component and livewire component, i'm in trouble

ZermattChris's avatar

@victorybiz It looks great, but without a simple working example, it's a shot-in-the-dark. Maybe a quick Tutorial, with working code, to go along with your github package?

Please :-)

1 like
Tithira's avatar

Just wrap your div withe wire:ignore and add wire"key=""uniqueKey a unique key for your input and add the vanilla js to the scripts or use alipne. Works fine. Wire:key does the job

<div class="form-group col-lg-12" wire:ignore>
   <input type="tel" id="phone" class="form-control " wire:key="uniqueKey">                                
 </div>

Please or to participate in this conversation.