Forms
Phone Number Field
Phone Number Field pairs a country/dial-code selector with a phone number input — UI pattern only, not SMS verification or carrier lookup.
State (Default/Focused/Error/Disabled) — 4 variants
betaReact AvailableFigma AvailableDocs Partial
- React last updated
- 2026-09-14
- Documentation last updated
- 2026-09-14
- Accessibility target
- WCAG 2.2 AA (target)
- Version
- 0.1.0-beta
Known open questions
- Figma flag is a generic two-stripe placeholder — React keeps it decorative (aria-hidden); country identity comes from Select option text.
- Default country list is illustrative (12 entries) — pass `countries` for production datasets.
- No national formatting engine — sanitization only allows digits and common phone punctuation.
Live preview
Country Select + type=tel number input. Flag is a decorative placeholder; country identity is the Select label.
Interactive
Value: US / —
Default with international number
Error
Disabled
Read-only
Purpose
Phone Number Field is a compound UI control pairing a country/dial-code selector with a phone number input as two adjacent bordered controls. It is a visual/input pattern only — not SMS verification, carrier lookup, or reachability checks.
Anatomy
PhoneNumberField = fieldset/legend + Country Selector (decorative flag placeholder + Select dial-code) + Number Input (type=tel) + optional supporting/error text.
Variants and states
default · focused · error · disabled
When to use
When documenting or collecting an international phone number where the dialing country matters. Override `countries` with your production country list.
When not to use
When you need OTP/SMS verification, number ownership confirmation, or carrier validation — use a dedicated verification service. For a plain national number with no country selector, use Text Input `type="tel"`.
Accessibility
fieldset + legend for the group; country Select and number input each have their own accessible names. Flag placeholder is decorative (aria-hidden); country identity comes from Select option text (name + dial code). Number input is type=tel with autocomplete=tel.
Keyboard behavior
Tab moves between country Select and phone number input. Select opens listbox with arrow keys; number input uses standard text editing.
Common mistakes
Treating the flag as the accessible country label. Assuming the default country list is complete. Treating sanitization as phone verification. Using type=number. Logging or persisting entered numbers from the design-system component.
Properties
Figma: State + Dial Code / Value text. React: label, country/defaultCountry/onCountryChange, value/defaultValue/onValueChange, countries, countryLabel/numberLabel, placeholder, disabled, readOnly, required, error, supportingText.
Does this verify the phone number?
No. It does not send SMS, check ownership, look up carriers, or confirm reachability. It is a UI input pattern only.
Are the flags real national flags?
No. Figma and React use a generic two-stripe placeholder. Accessible country identity is the Select option label (name + dial code).
Tokens used
component/radius/controlsemantic/border/defaultsemantic/focus-ringsemantic/text/danger
Known limitation
Flag is a generic two-stripe placeholder, not real national flags. Default country list is illustrative (12). No national formatting engine — digits and common punctuation (+ spaces () . -) are allowed; no E.164 ownership claim. /r deferred to CE-3. Does not send network requests or verify numbers.
Component API
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | — | Visible fieldset legend for the compound control. |
| country | string | — | Controlled country option value (e.g. ISO alpha-2). |
| defaultCountry | string | — | Uncontrolled initial country option value. |
| onCountryChange | (country: string) => void | — | Fires when the selected country changes. |
| value | string | — | Controlled phone number string (sanitized punctuation allowed). |
| defaultValue | string | — | Uncontrolled initial phone number string. |
| onValueChange | (value: string) => void | — | Fires with the sanitized phone number after edits/paste. |
| countries | PhoneCountryOption[] | — | Country options ({ value, dialCode, label }). Defaults to a small illustrative list. |
| countryLabel | string | "Country" | Accessible name for the country selector. |
| numberLabel | string | "Phone number" | Accessible name for the phone number input. |
| placeholder | string | "Phone number" | Placeholder for the number input. |
| disabled | boolean | false | Disables country selector and number input. |
| readOnly | boolean | false | Read-only number input; country selector is non-editable. |
| required | boolean | false | Marks the group and both controls required. |
| error | string | — | Error message; sets invalid chrome on both controls. |
| supportingText | string | — | Help text when no error is present. |
React example
Copy React example
import { useState } from "react";
import { PhoneNumberField } from "@/components/ui/PhoneNumberField";
export function Example() {
const [country, setCountry] = useState("US");
const [value, setValue] = useState("");
return (
<PhoneNumberField
label="Mobile number"
country={country}
onCountryChange={setCountry}
value={value}
onValueChange={setValue}
supportingText="UI pattern only — not SMS verification or carrier lookup."
/>
);
}