Components

customphonenumber

A phone number input backed by intl-tel-input with a country-code flag dropdown and format validation.

A phone number input backed by intl-tel-input with a country-code flag dropdown and format validation. Always use this instead of input with type: "tel".

Read Form Rules before using this component — keys, labels, required fields, expressions, visibility, and validation all follow shared conventions.

When to use

  • Any field that captures a phone number

When NOT to use

Instead of customphonenumber, use…For…
input with type: "email"Email addresses
customidinputNational ID / document numbers

Never use input with type: "tel" for phone numbers — use this component.

Props

PropTypeRequired?Description
labelstringrequiredVisible label. Must be unique across the form.
requiredbooleanrequiredAlways false. The expression controls the runtime value.
defaultRequiredbooleanrequiredtrue for required fields, false for optional ones.
initialCountrystringoptionalISO 3166-1 alpha-2 country code pre-selected in the flag dropdown (e.g. "rw"). Lowercase.
preferredCountriesstring[]optionalCountry codes pinned to the top of the dropdown (e.g. ["rw"]).
onlyCountriesstring[]optionalWhen set, the dropdown shows only these countries.
excludeCountriesstring[]optionalCountry codes removed from the dropdown.
allowDropdownbooleanoptionalfalse hides the country flag dropdown and locks the country.
countryNoValidationbooleanoptionaltrue validates format against the selected country's rules. false accepts any digit sequence.
configDetailsobjectoptionalAlternative to the flat props above using { label, value } objects. See below.
prefillCountryCodeFromstringoptionalKey of another form field whose value auto-sets the country code.
placeholderstringoptionalGhost text shown inside the field.
hintstringoptionalHelp text rendered below the field.
readonlybooleanoptionalRenders the field non-editable.
hideFieldbooleanoptionalHides the field and excludes its value. Toggle via expressions["props.hideField"].

configDetails (alternative to flat country props)

Use configDetails with { label, value } objects instead of the flat string props:

"configDetails": {
  "initialCountry": { "label": "Rwanda", "value": "RW" },
  "preferredCountries": [{ "label": "Rwanda", "value": "RW" }],
  "onlyCountries": [],
  "excludeCountries": []
}

Validation

invalidNumberFormat is a named validator and must appear in both validators.validation and validation.messages. Without it in validators.validation, the format message never fires.

Examples

Rwanda-only phone number (standard pattern)

{
  "key": "PHONE_NUMBER",
  "type": "customphonenumber",
  "props": {
    "label": "Phone Number",
    "placeholder": "Enter phone number",
    "required": false,
    "defaultRequired": true,
    "initialCountry": "rw",
    "preferredCountries": ["rw"],
    "allowDropdown": false,
    "countryNoValidation": true
  },
  "expressions": {
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {
      "required": "Phone Number is required.",
      "invalidNumber": "Provided number is invalid.",
      "invalidNumberFormat": "Number format is invalid."
    }
  },
  "validators": {
    "validation": ["invalidNumberFormat"]
  }
}

International phone number with country dropdown

{
  "key": "APPLICANT_PHONE",
  "type": "customphonenumber",
  "props": {
    "label": "Phone Number",
    "placeholder": "Enter phone number",
    "required": false,
    "defaultRequired": true,
    "allowDropdown": true,
    "initialCountry": "rw",
    "preferredCountries": ["rw"],
    "countryNoValidation": true
  },
  "expressions": {
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {
      "required": "Phone Number is required.",
      "invalidNumber": "Provided number is invalid.",
      "invalidNumberFormat": "Number format is invalid."
    }
  },
  "validators": {
    "validation": ["invalidNumberFormat"]
  }
}

Common mistakes

  • Omitting validators.validation: ["invalidNumberFormat"] — the format message never fires without it.
  • Using onlyCountries and excludeCountries together — onlyCountries already defines an allowlist; excludeCountries is redundant.
  • Mixing flat string props (initialCountry: "rw") and configDetails objects — pick one format and use it consistently.
  • Using input with type: "tel" for phone numbers — always use this component.

Checklist

  • key is UPPER_SNAKE_CASE and unique across the entire form
  • props.label is present, unique, and correctly cased
  • Field is nested at the correct depth: sections > formly-group > block > customphonenumber
  • required: false is set (never true)
  • defaultRequired is set
  • expressions["props.required"] is present with the exact required expression
  • validation.messages contains required, invalidNumber, and invalidNumberFormat
  • validators.validation contains "invalidNumberFormat"
  • initialCountry and preferredCountries are set (default to Rwanda: "rw", ["rw"])
  • Not using input with type: "tel" anywhere in the form

On this page