Skip to Content

PhoneNumberField

A phone number field allows users to enter and edit phone numbers using a keyboard.

Usage

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.

Examples

With Label and Description

Provide clear instructions to users with labels and descriptions.

The contact number of the individual.

Local Variant

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").

Placeholder Modes

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.

With Custom Placeholder

Use the placeholder prop to show custom placeholder text. In "polite" mode (the default), the custom placeholder takes precedence over the example number.

Default Country

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.

Country Options Order

Use the countryOptionsOrder prop to control which countries appear at the top of the country selector dropdown.

Controlled

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

With Error Message

Combine isInvalid and errorMessage props to show validation errors.

Please enter a valid contact number.

With Validation

Use the isPossiblePhoneNumber utility function (re-exported from react-phone-number-input) to validate phone numbers on change.

Sizes

Use the size prop to change the size of the phone number field.

Disabled

Use the isDisabled prop to disable the phone number field.

Utility Functions

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"

Accessibility

  • Built with a native <input type="tel"> element with autocomplete="tel"
  • Country selector is keyboard accessible with built-in search
  • Full keyboard support for country selection and phone number entry
  • Proper ARIA labeling and descriptions
  • Invalid and disabled states exposed to assistive technology
  • Country flags include accessible country name labels

Slots

  • base: The root container wrapper
  • group: The field group containing the country selector and input
  • wrapper: The wrapper around the phone input elements
  • label: The label text element
  • input: The phone number input element
  • description: The description text below the field
  • error: The error message text
  • select: The country selector wrapper
  • selectTrigger: The country selector button
  • selectIcon: The dropdown icon in the country selector
  • selectItem: Each item in the country dropdown list
  • selectItemLabel: The country name label in each dropdown item
  • selectItemCountryCode: The calling code text in each dropdown item (e.g. "+65")
  • flag: The country flag element
  • selectList: The country dropdown list container
  • selectPopover: The country dropdown popover container

Data Attributes

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):

  • data-variant: The current variant of the field ("international" or "local"). Based on variant prop.
  • data-invalid: When the input is invalid. Based on isInvalid prop.
  • data-disabled: When the input is disabled. Based on isDisabled prop.

Custom Styles

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",
  }}
/>

Props

PhoneNumberField

PropTypeDefaultDescription
labelReact.ReactNode-The label for the phone number field
descriptionReact.ReactNode-The description text shown below the field
errorMessageReact.ReactNode | ((validation: ValidationResult) => string)-The error message to display when validation fails
valueE164Number-The current value in E.164 format (controlled)
defaultValueE164Number-The default value in E.164 format (uncontrolled)
onChange(value: E164Number | undefined) => void-Callback fired when the value changes
defaultCountryCountry"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
placeholderstring-Custom placeholder text for the input
examplesRecord<Country, string>Mobile examplesCustom example phone numbers per country for placeholders
internationalbooleanfalseWhether to display numbers in international format
addInternationalOptionbooleanfalseWhether to add an "International" option to the country selector
countryOptionsOrderCountry[]["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
isDisabledbooleanfalseWhether the field is disabled
isInvalidbooleanfalseWhether the field should display as invalid
classNamesSlotsToClasses<PhoneNumberFieldSlots>-Custom CSS classes for component slots