PhoneInput
Country-aware phone number input that emits E.164 values.
Quick Preview
Usage
<PhoneInput value={phone} onChange={setPhone} defaultCountry="NG" />onChange always receives E.164 — "+2348012345678" — or undefined when
nothing dialable has been typed yet.
Examples
Default PhoneInput
Use this as the starting point for PhoneInput. Keep product data, routing, fetching, and authorization logic in the consuming app.
National and international entry
The same number can be written either way round, and both are accepted.
0801 234 5678 is read against the selected country, national trunk prefix and
all. A leading + — typed or pasted — switches the field to international
entry: the number keeps its own calling code, the country selector follows the
digits as soon as they name one country, and the selector stops repeating the
code the field is already showing.
Type 0801 234 5678 or paste +234 801 234 5678. A leading + switches to international entry and moves the country selector to match.
Emitted value: undefined
Picking a country from the selector rewrites the code in front of the digits
rather than discarding them, so switching from Nigeria to Ghana turns
+234 801 234 5678 into +233 801 234 5678.
Numbers group as they are typed whether or not the trunk prefix is there:
8161827754 reads as 816 182 7754 and 08161827754 as 0816 182 7754. Most
countries only publish a national format that assumes the prefix, so the second
grouping is borrowed from the international pattern with the calling code taken
back off — the digits shown are always the digits typed.
Trailing addon
rightAddon pins content to the trailing edge of the field — a validity tick, a
"Verify" button, an extension field. It sits outside the number, so it never
shifts as the number is formatted.
Props
| Prop/API | Type | Default | Description |
|---|---|---|---|
value | string | - | Controlled E.164 phone value. |
onChange | (value: string | undefined) => void | - | Called with the next E.164 value, or undefined when the field holds nothing dialable. |
defaultCountry | Country code | "NG" | Country the field starts on, before anything is typed. |
rightAddon | ReactNode | - | Content pinned to the trailing edge of the field. |
size | "sm" | "md" | "lg" | { base, md?, lg? } | "md" | Field scale. Inherits from SizeProvider. |
disabled | boolean | false | Disables the field and the country selector. |
readOnly | boolean | false | Makes the number uneditable. |
placeholder | string | "(0000) 000-0000" | Placeholder for the number, not the calling code. |
id, name | string | - | Forwarded to the underlying input. |
aria-invalid | boolean | - | Marks the field invalid. |
className | string | - | Local layout or spacing overrides. |
Validate the emitted value with validatePhoneNumber from
@giddaa-housing/ui/utils/phone rather than a regex —
it is the same data set the field formats with.
Accessibility
- Provide visible labels or accessible names for interactive controls.
- The country selector returns focus to the number field on every close —
selection,
Escape, or an outside click — so the tab order does not jump. - Anything interactive in
rightAddonneeds its own accessible name; it is outside the field's label. - Preserve the component-provided focus, keyboard, disabled, and invalid-state behavior.
- Do not communicate state with color alone; include text, icons, or helper copy.