Skip to content

InputController

A state controller for a phone-number field. Every state-changing call returns the next InputState to write back. The controller holds the region, the filters, and the history.

function createNationalInputController(config: NationalInputControllerConfig): InputController;

Creates a controller for one region’s national format. The calling code never appears in the field.

const controller = createNationalInputController({ defaultRegion: 'US' });
controller.insert('', '4155550132', 0, 0);
// { value: '(415) 555-0132', region: 'US', selectionStart: 14, selectionEnd: 14 }
Field Type Meaning
defaultRegion RegionCode Required. The region the field formats for.
strict boolean Restricts validity to defaultRegion, as in parsePhoneNumber.
initialValue string Seeds the field with a starting value, outside the history.
maxHistorySize number Bounds the undo and redo history; 150 entries by default, dropping the oldest first.
function createInternationalInputController(config?: InternationalInputControllerConfig): InputController;

Creates a controller that resolves the region from the value. The calling code lives in the field unless display.callingCodeInInput is false, which requires defaultRegion.

const controller = createInternationalInputController();
controller.setValue('+14155550132');
// { value: '1 415-555-0132', region: 'US', selectionStart: 14, selectionEnd: 14 }

defaultRegion, strict, initialValue, and maxHistorySize match NationalInputControllerConfig. defaultRegion is required only when the calling code is kept out of the field. When the calling code is in the field, defaultRegion pre-fills the field with that region’s code.

display, an InternationalDisplayConfig, places the calling code:

display The field holds
omitted Calling-code digits, with no + rendered
{ callingCodeInInput: true, plusPrefix } Calling-code digits; plusPrefix decides whether the + shows
{ callingCodeInInput: false } The international significant number; the region comes from defaultRegion and setRegion

plusPrefix, a PlusPrefixMode, controls the leading +. 'none' never shows it, 'fixed' always shows it, and 'erasable' shows it while the value starts with one. Under 'erasable', backspace right after the + removes it. A value set without a + starts without it, while the calling code seeded from defaultRegion starts with it.

interface InputState {
readonly value: string;
readonly region: RegionCode | null;
readonly selectionStart: number;
readonly selectionEnd: number;
}

The next value and selection to apply to the field. value is the formatted string; the selection indices point into it.

region is the region the value resolves to, or null when none does. Within a shared calling code the digits decide. A 604 number typed into a US field reports CA, unless the field is strict, which keeps reporting its defaultRegion. A field with no digits reports the configured default region, which keeps the region stable when the value is cleared.

The three edits take the field’s current value and selection. Pass what the field shows. A value the controller never rendered, such as an autofill, is read from scratch. setValue takes the new value.

insert(value: string, text: string, selectionStart: number, selectionEnd: number): InputState;

Replaces the selection from selectionStart to selectionEnd in value with text, then reformats. text can be one keystroke or a whole paste. Digits are read in ASCII, in fullwidth, and in the two Arabic-Indic scripts. A paste that starts with a + and carries a whole number replaces the value with that number, minus any written trunk prefix and extension. With the calling code outside the field, the region switches to the number’s own, while a national field accepts the number only under its own calling code and a strict field keeps its region. Anything else reads as digits.

deleteBackward(value: string, selectionStart: number, selectionEnd: number): InputState;

Deletes the selection, or the digit before the caret when the selection is empty, then reformats. Formatting characters are skipped. With the caret right after ) in (415) 555-0132, one call removes the 5 before it.

deleteForward(value: string, selectionStart: number, selectionEnd: number): InputState;

Mirrors deleteBackward for the digit after the caret.

setValue(value: string): InputState;

Replaces the whole value and reformats, as for a paste or a programmatic set. A value that carries a plus before any digit follows the paste rule of insert.

Every change here re-resolves the value already in the field.

setRegion(region: RegionCode): InputState;

Switches to region and reformats the current digits the way that region writes them. With the calling code in the field, the field swaps in the calling code of region and keeps the national digits. A field holding 1 416-555-0132 switched to DE reads 49 4165 550132. The digits still decide the reported region. With digits in the field, switching between two regions of one calling code changes nothing.

setRegionFilter(regions: readonly RegionCode[] | null): InputState;

Restricts which regions the value may resolve to, or null to allow all. Every PhoneNumber query answers within the allowed set. A filter that excludes every region of the value’s calling code reports INVALID_CALLING_CODE.

setNumberTypeFilter(numberTypes: readonly NumberType[] | null): InputState;

Restricts which number types the value may resolve to, or null to allow all. A filter that leaves no possible length for the value’s calling code reports INVALID_CALLING_CODE.

The four edits and setRegion push a new entry onto the history when they change the state. The two filters replace the current entry.

undo(): InputState;

Steps back to the previous state in history. With nothing to undo, it returns the current state.

redo(): InputState;

Steps forward again after an undo. With nothing to redo, it returns the current state.

readonly canUndo: boolean;

Whether there is history to undo. initialValue seeds the field outside the history, leaving a freshly created controller at false.

readonly canRedo: boolean;

Whether there is history to redo.

clearHistory(): void;

Drops the undo and redo history.

Reading changes nothing.

getPhoneNumber(): PhoneNumber;

The current value as a PhoneNumber to query. For a national field it equals parsePhoneNumber of the displayed value with the field’s defaultRegion and strict. For an international field with the calling code in the field it equals parsePhoneNumber of the displayed value. strict on an international field and any active filter narrow the result further and have no parsePhoneNumber equivalent.

With the calling code kept out of the field (callingCodeInInput: false), the digits are read as typed behind the selected region’s calling code, with no trunk prefix stripped. A typed national (trunk) prefix there reports NATIONAL_PREFIX_PRESENT.

readonly currentState: InputState;

The value and selection as they stand.

The conformance suite types enumerated inputs into a controller character by character and checks on each one that getPhoneNumber equals parsePhoneNumber of the displayed value, which holds the controllers to the same parity as the Google-compared parsePhoneNumber. The numbers are on Verified.