K

Forms

PhoneInput

A dialling-code select beside a national number, stored as one E.164 string.

On this page

An international phone number: the country prefix is picked from a list, the rest is typed, and the two are one value. Reach for it when the number will be dialled, exported or matched later — a TextInput::make()->tel() accepts anything a person types, including a national number nobody outside that country can call.

use NyonCode\WireForms\Components\PhoneInput;

How It Works

The prefix lives inside the value, not beside it. State holds the written international number — +420 123 456 789 — and the controller splits it for display on every render, putting it back together on every keystroke. A field that kept the country separately would need a second column to persist it, or would lose it: a number whose prefix exists only in the UI cannot be dialled from the database.

What is stored is the same number without its spacing, which is E.164: +420123456789. The spacing is presentation, applied by hydrateState() on the way in and stripped by dehydrateState() on the way out.

Grouping is applied in threes, and a trailing single digit joins the group before it+1 212 555 1234, not +1 212 555 123 4. The controller writes the same grouping in the browser as PHP does on the server.

The national part is not reformatted while it is being typed. Regrouping on every keystroke moves the caret to the end of the input, which makes editing the middle of a number impossible.

The country list is a curated table (Support\DialingCodes), not a copy of the ITU register: each entry carries the dialling code and the digit range that country issues, which is what makes a typed number checkable at all. Options read as a flag and a prefix — 🇨🇿 +420 — and the flag is computed from the ISO code rather than stored, so it cannot fall out of step with it.

A prefix is not unique. +1 is the whole North American plan, so matching a number to a country answers with the first entry holding that prefix. The choice is cosmetic: it decides which flag the select shows, never whether the number is valid, because countries sharing a prefix share its digit range.

Validation asks three questions in order, and each has its own message: is the number international at all (a leading +), is its prefix one this field offers, and does the national part have as many digits as that country issues. A country outside the table is held to E.164's own bounds — 4 to 15 digits — which is the most a table-free check can say.

The offer can be set once, for the whole application. config('wire-forms.phone.countries') and default_country are what a field falls back to; naming them per field is for the exceptions.

Basic Usage

PhoneInput::make('phone')

Every country in the table, opening on Czechia.

Restricting The Countries

PhoneInput::make('phone')
->countries(['CZ', 'SK', 'DE', 'AT']) // in the order they are listed

The list is also the validation: a +49 number is rejected by a field that offers only CZ and SK. An ISO code the table does not carry is dropped rather than offered as a dead option.

Choosing Where It Opens

PhoneInput::make('phone')
->countries(['CZ', 'SK', 'DE'])
->defaultCountry('DE') // the first offered country by default

The default applies while the field is empty; a field holding a number opens on that number's country.

Extended Example

use Livewire\Component;
use NyonCode\WireForms\Components\PhoneInput;
use NyonCode\WireForms\Components\TextInput;
use NyonCode\WireForms\Forms\Form;
use NyonCode\WireForms\Forms\WithForms;
 
class EditContact extends Component
{
use WithForms;
 
public array $data = [];
 
public function mount(Contact $contact): void
{
$this->form->fill($contact->attributesToArray());
}
 
public function form(Form $form): Form
{
return $form
->model(Contact::class)
->statePath('data')
->schema([
TextInput::make('name')->required(),
PhoneInput::make('phone')
->countries(['CZ', 'SK', 'PL', 'DE'])
->defaultCountry('CZ')
->required(),
]);
}
}

The column holds +420123456789, ready to be dialled, exported or matched against another system's number without normalising it first.

PhoneInput API

The phone surface. Label, hint, placeholder, visibility and the rest are the shared field API, documented in Form Fields.

->countries(array $countries) // ISO 3166-1 alpha-2 codes — default: config('wire-forms.phone.countries')
->defaultCountry(string $country) // where an empty field opens — default: config('wire-forms.phone.default_country')
->getCountries(): array // array<int, DialingCode>
->getDefaultCountry(): ?DialingCode
->getCountryOptions(): array // array<int, array{country: string, dialingCode: string, label: string}>
  • Form Fields — the shared field API
  • TextInput — for a number that is never dialled programmatically
  • Validation — how implicit rules join the ones you write