Build a phone field
createPhoneInput turns a plain <input> into a phone
field. This guide builds an international one. The widget handles the events, the value, the caret,
and the history, while your renderStatus function draws the status line.
Live demo
Section titled “Live demo”Type +14155550132. The field formats it live to +1 415-555-0132 and the status reads
Valid: US +14155550132. Type +442071838750 instead and the field shows +44 20 7183 8750,
because the calling code selects the region.
Edit in the middle of the number and the caret stays on the same digit while the groups reflow
around it. Paste the number in any spelling that carries the calling code, +1 (415) 555-0132 or
tel:+14155550132, and it lands as +1 415-555-0132. Backspace and Delete skip the formatting and
remove the nearest digit in one press. Undo and redo use Cmd/Ctrl+Z and Cmd/Ctrl+Shift+Z. A number
with too few digits shows TOO_SHORT.
The code
Section titled “The code”The demo and the source are the same three files. The markup is an input and a status line. The
script is one createPhoneInput call in international mode with an
erasable plus.
renderStatus draws the status from each emitted state.
<div id="phone-field"> <label for="phone-field-input">Phone number</label> <input id="phone-field-input" type="tel" placeholder="+1 201-555-0123" /> <p class="phone-field-status"></p></div>#phone-field { --surface: #ffffff; --text: #1c1f1e; --muted: #66716d; --border: #c9d1ce; --accent: #26997b; --valid: #1d7a5f; --error: #b3384f;
color: var(--text);}
#phone-field label { display: block; margin-bottom: 0.375rem; font-size: 0.875rem; font-weight: 600;}
#phone-field input { width: 100%; padding: 0.5rem 0.75rem; border: 1px solid var(--border); border-radius: 0.375rem; background: var(--surface); color: inherit; font-size: 1rem; font-variant-numeric: tabular-nums;}
#phone-field input:focus-visible { border-color: var(--accent); outline: none; box-shadow: 0 0 0 1px var(--accent);}
#phone-field input::placeholder { color: var(--muted);}
#phone-field .phone-field-status { margin: 0.5rem 0 0; min-height: 1.25rem; font-size: 0.875rem; color: var(--muted);}
#phone-field .phone-field-status[data-tone='valid'] { color: var(--valid);}
#phone-field .phone-field-status[data-tone='error'] { color: var(--error);}import { ensureEngineReady } from '@telixon/core';import { createPhoneInput } from '@telixon/web-sdk';
await ensureEngineReady();
const input = document.querySelector('#phone-field input');const status = document.querySelector('#phone-field .phone-field-status');
const phone = createPhoneInput({ mode: 'international', display: { callingCodeInInput: true, plusPrefix: 'erasable' }, input,});
function renderStatus(state) { if (state.value === '') { status.textContent = 'Type a number.'; status.dataset.tone = ''; return; }
if (state.validationError === null) { status.textContent = 'Valid: ' + state.region + ' ' + phone.getPhoneNumber().formatE164(); status.dataset.tone = 'valid'; return; }
status.textContent = state.validationError.kind; status.dataset.tone = 'error';}
phone.subscribe(renderStatus);renderStatus(phone.getState());Covered events lists every input type PhoneInput handles,
IME composition and drag-and-drop included. A region picker usually sits next to this field.
Build a region picker adds one.