Build a phone input
A phone input pairs a plain <input> with an
InputController. The field emits edits; the controller
returns the next state to write back.
Create the controller
Section titled “Create the controller”A single-region form takes a national controller. For a field that accepts any region, jump to the international field.
import { createNationalInputController } from '@telixon/core';
const controller = createNationalInputController({ defaultRegion: 'US' });Wire the field
Section titled “Wire the field”Translate the field’s beforeinput events into controller calls. Write each returned state back:
<input id="phone" type="tel" autocomplete="tel" />import type { InputState } from '@telixon/core';
const input = document.querySelector<HTMLInputElement>('#phone')!;
function apply(state: InputState) { input.value = state.value; input.setSelectionRange(state.selectionStart, state.selectionEnd);}
input.addEventListener('beforeinput', (event) => { event.preventDefault(); const value = input.value; const start = input.selectionStart ?? 0; const end = input.selectionEnd ?? 0;
if (event.inputType === 'deleteContentBackward') { apply(controller.deleteBackward(value, start, end)); } else if (event.inputType === 'deleteContentForward') { apply(controller.deleteForward(value, start, end)); } else { const text = event.data ?? event.dataTransfer?.getData('text') ?? ''; apply(controller.insert(value, text, start, end)); }});Typing 4155550132 leaves the field showing (415) 555-0132, with the caret after the last
digit. A paste flows through the same handler. This minimal handler stops at typing, paste, and
plain deletes; word deletes, line deletes, and IME composition need branches of their own, which
PhoneInput from @telixon/web-sdk already wires for production.
Undo and redo
Section titled “Undo and redo”The controller already holds the history; wire the keys to it:
input.addEventListener('keydown', (event) => { if (!event.metaKey && !event.ctrlKey) return; const key = event.key.toLowerCase(); if (key !== 'z' && key !== 'y') return; event.preventDefault(); const isRedo = (key === 'z' && event.shiftKey) || key === 'y'; apply(isRedo ? controller.redo() : controller.undo());});Read the number
Section titled “Read the number”getPhoneNumber answers for the current value at any moment, mid-typing included:
controller.insert('', '4155550132', 0, 0);
controller.getPhoneNumber().isValid(); // truecontroller.getPhoneNumber().formatE164(); // '+14155550132'The full query surface is available on that number, including the possibility check and the typed validation error; see Validate a phone number.
The international field
Section titled “The international field”A field that takes numbers from anywhere switches to the international controller. The region follows the digits from the first keystroke:
import { createInternationalInputController } from '@telixon/core';
const controller = createInternationalInputController();
let state = controller.insert('', '1', 0, 0);// { value: '1 ', region: 'US', selectionStart: 2, selectionEnd: 2 }
state = controller.insert(state.value, '4155550132', 2, 2);// { value: '1 415-555-0132', region: 'US', selectionStart: 14, selectionEnd: 14 }The display modes, including the leading +, are under
InternationalInputControllerConfig.
Restrict number types
Section titled “Restrict number types”A field for one kind of number filters the rest out. A support-line field takes only toll-free numbers:
const supportLine = createNationalInputController({ defaultRegion: 'US' });supportLine.setNumberTypeFilter(['TOLL_FREE']);
supportLine.setValue('8002345678');supportLine.getPhoneNumber().isValid(); // true
supportLine.setValue('4155550132');supportLine.getPhoneNumber().isValid(); // false