A phone number field allows users to enter and edit phone numbers using a keyboard.
import { PhoneNumberField } from "@opengovsg/oui"<PhoneNumberField label="Contact number" />The PhoneNumberField component provides an accessible phone number input with a built-in country selector. It is built on top of react-phone-number-input and stores values in E.164 international format (e.g. +6591234567).
By default, the country selector is set to Singapore (SG) and the input displays an example phone number as a placeholder for the selected country.
If the component does not have a visible label (by passing a label prop), an aria-label or aria-labelledby prop must be passed instead to identify it to assistive technology.
Provide clear instructions to users with labels and descriptions.
Use the variant="local" prop to render a simplified phone number field without the country selector. This is useful when only local phone numbers are expected. The field displays the country flag based on the defaultCountry prop (defaults to "SG").
The placeholderMode prop controls how the input placeholder behaves in relation to example phone numbers for the selected country.
"polite" (default): Uses the example number as placeholder only if no custom placeholder prop is provided."aggressive": Always replaces the placeholder with the example number for the selected country."off": Never uses example numbers as placeholders.Use the placeholder prop to show custom placeholder text. In "polite" mode (the default), the custom placeholder takes precedence over the example number.
Use the defaultCountry prop to set the initially selected country. Defaults to "SG" (Singapore).
The default country will also be ordered at the top of the country selector dropdown, unless overridden by the countryOptionsOrder prop.
Use the countryOptionsOrder prop to control which countries appear at the top of the country selector dropdown.
Use the value and onChange props to control the phone number value programmatically. The value is stored in E.164 format (e.g. "+6591234567").
Value: empty
Combine isInvalid and errorMessage props to show validation errors.
Use the isPossiblePhoneNumber utility function (re-exported from react-phone-number-input) to validate phone numbers on change.
Use the size prop to change the size of the phone number field.
Use the isDisabled prop to disable the phone number field.
PhoneNumberField re-exports the following utility functions from react-phone-number-input:
formatPhoneNumber(value): Formats an E.164 phone number to national format (e.g. "8123 4567").formatPhoneNumberIntl(value): Formats an E.164 phone number to international format (e.g. "+65 8123 4567").parsePhoneNumber(value): Parses an E.164 phone number string into a PhoneNumber object with properties like country, nationalNumber, and number.isPossiblePhoneNumber(value): Returns true if the phone number has a valid length for its country. This is the recommended validation approach.import {
formatPhoneNumber,
formatPhoneNumberIntl,
isPossiblePhoneNumber,
parsePhoneNumber,
} from "@opengovsg/oui"<input type="tel"> element with autocomplete="tel"PhoneNumberField has the following attributes on the base element, which you can use to style the component based on its state (e.g. group-[data-invalid=true]:bg-red-500):
"international" or "local"). Based on variant prop.isInvalid prop.isDisabled prop.You can customize the PhoneNumberField component by passing custom Tailwind CSS classes to the component slots via the classNames prop.
<PhoneNumberField
label="Contact number"
classNames={{
base: "max-w-xs",
input: "text-right",
flag: "rounded-md",
}}
/>| Prop | Type | Default | Description |
|---|---|---|---|
label | React.ReactNode | - | The label for the phone number field |
description | React.ReactNode | - | The description text shown below the field |
errorMessage | React.ReactNode | ((validation: ValidationResult) => string) | - | The error message to display when validation fails |
value | E164Number | - | The current value in E.164 format (controlled) |
defaultValue | E164Number | - | The default value in E.164 format (uncontrolled) |
onChange | (value: E164Number | undefined) => void | - | Callback fired when the value changes |
defaultCountry | Country | "SG" | The initially selected country |
onCountryChange | (country: Country) => void | - | Callback fired when the selected country changes |
placeholderMode | "polite" | "aggressive" | "off" | "polite" | Controls how example number placeholders are shown |
placeholder | string | - | Custom placeholder text for the input |
examples | Record<Country, string> | Mobile examples | Custom example phone numbers per country for placeholders |
international | boolean | false | Whether to display numbers in international format |
addInternationalOption | boolean | false | Whether to add an "International" option to the country selector |
countryOptionsOrder | Country[] | ["SG"] | Countries to display at the top of the selector |
variant | "international" | "local" | "international" | Whether to use the international phone input with country select or a local-only input with a fixed country flag |
size | "xs" | "sm" | "md" | "md" | The size of the component |
isDisabled | boolean | false | Whether the field is disabled |
isInvalid | boolean | false | Whether the field should display as invalid |
classNames | SlotsToClasses<PhoneNumberFieldSlots> | - | Custom CSS classes for component slots |