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, with the + under plusPrefix
{ callingCodeInInput: false } The international significant number; the region comes from defaultRegion and setRegion

plusPrefix, a PlusPrefixMode, renders the leading +, with 'none' never showing it, 'fixed' always, and 'erasable' while the value carries one. Under 'erasable', backspace right after the + removes it. Every plus-less start, an empty or omitted initialValue included, begins with the plus erased, leaving an empty field truly empty; only the calling-code seed from defaultRegion keeps the visible plus.

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 it reports the resolved owner of the digits, where a 604 number comes back as CA even in a US-configured field. A field with no digits reports the configured default region, keeping the region stable when the value is cleared.

All four take the field’s value as an argument, keeping the controller working from what the field actually shows.

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.

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

Deletes the selection, or the character before the caret when the selection is empty, then reformats. When that character is a formatting character, the call snaps the caret across it to the nearest digit without deleting; the next delete removes the digit itself.

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

Mirrors deleteBackward for the character after the caret.

setValue(value: string): InputState;

Replaces the whole value and reformats, as for a paste or a programmatic set.

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. Where the calling code lives in the field, the digits keep deciding the region. Where the field holds the international significant number, the switch applies.

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, equal to parsePhoneNumber of the displayed value, with the national controller’s defaultRegion and strict carried along. Active filters have no parsePhoneNumber equivalent and narrow the result further.

With the calling code kept out of the field (callingCodeInInput: false), the digits resolve literally as the international significant number behind the selected region’s calling code. 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 through a controller, character by character, requiring the getPhoneNumber equality on every input. Since parsePhoneNumber is the Google-compared path, the controllers are held to the same parity; see Verified.