Components

customidinput

An ID number input with live external verification. Validates against NIDA/NIN registries and auto-populates downstream fields from the API response.

An ID number input with live external verification. Validates against NIDA/NIN registries and auto-populates downstream fields from the API response.

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

When to use

  • Capturing a Rwandan National ID (NID), Foreigner ID, Refugee ID, Child ID, or NIN with live registry verification
  • Any document ID that must be validated against an external registry

When NOT to use

Instead of customidinput, use…For…
inputPlain text reference numbers with no external verification
customtininputTIN (Tax Identification Number) — never use customidinput for TINs
customphonenumberPhone numbers

ID type reference

Every customidinput requires idType. For idType: "NID", nidType is also required and controls which NID prefix is accepted.

idTypenidTypeidLengthendpointCodeusePrefetch
NIDNATIONAL_ID16NIDAGETIDINFOtrue
NIDFOREIGNER_ID16NIDAGETIDINFOfalse
NIDREFUGEE_ID16NIDAGETIDINFOfalse
CHILD_ID8NIDAGETCHILDINFOfalse
NIN10not requiredfalse

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.
idType'NID' | 'CHILD_ID' | 'NIN'requiredDocument type being collected.
nidType'NATIONAL_ID' | 'FOREIGNER_ID' | 'REFUGEE_ID'required when idType is 'NID'NID subtype. Controls accepted prefix: NATIONAL_ID starts with 1, REFUGEE_ID with 2, FOREIGNER_ID with 3.
idLengthnumberrequiredExpected digit count. 16 for NID, 8 for CHILD_ID, 10 for NIN.
useBaseUrlbooleanrequiredAlways true — prepends the API gateway base URL.
endpointCodestringrequired for NID and CHILD_IDIntegration endpoint code. Not required for NIN.
usePrefetchbooleanoptionaltrue auto-fetches the citizen's registered ID from their profile when the field becomes visible. Only works for NATIONAL_ID — always false for FOREIGNER_ID, REFUGEE_ID, CHILD_ID.
populatesarrayoptional{ valueKey, targetKey } pairs mapping API response keys to form field keys. Must be an array, not an object.
idConditionsobjectoptionalAge constraint applied after fetch. See below.
placeholderstringoptionalGhost text shown inside the field.
readonlybooleanoptionalRenders the input non-editable.
hintstringoptionalHelp text shown below the field.
tooltipstringoptionalTooltip shown on hover.
hideFieldbooleanoptionalHides field and excludes its value. Toggle via expressions["props.hideField"].

idConditions.ageLimit

Enforces a minimum and/or maximum age after the ID lookup. key must be a valueKey returned by the endpoint (usually "dateOfBirth"). Age bounds are in years.

"idConditions": {
  "ageLimit": {
    "key": "dateOfBirth",
    "minimumAge": 18,
    "maximumAge": 64
  }
}

When used, add "minimumAge" and/or "maximumAge" to validators.validation and include their messages in validation.messages.

API response keys (populates.valueKey)

NIDAGETIDINFO (idType: "NID")

valueKeyDescription
surnameFamily name
forenameGiven name(s)
fatherNameFather's name
motherNameMother's name
dateOfBirthDate of birth
sexGender
nationalityNationality
countryOfBirthCountry of birth
placeOfBirthPlace of birth
civilStatusCivil / marital status
citizenStatusLiveness — "ALIVE", "DEAD", or "DECEASED"

NIDAGETCHILDINFO (idType: "CHILD_ID")

valueKeyDescription
surnameFamily name
forenameGiven name(s)
fatherNameFather's name
motherNameMother's name
dateOfBirthDate of birth
sexGender
countryOfBirthCountry of birth
placeOfBirthPlace of birth
civilStatusCivil / marital status

Validation messages

KeyWhen it fires
requiredField is empty and required
invalidIdID does not pass format check
invalidInputID does not match expected idLength
invalidNidInputID is not a valid NID for the given nidType
verificationFailedNIDA API call failed (network / server error)
verificationInvalidID not found in NIDA records
verificationRequiredUser has not confirmed consent
endpointCodeNotConfiguredendpointCode is missing — field locks as read-only

Examples

National ID with population and liveness check

{
  "key": "APPLICANT_NID",
  "type": "customidinput",
  "props": {
    "label": "National ID Number",
    "idType": "NID",
    "nidType": "NATIONAL_ID",
    "idLength": 16,
    "useBaseUrl": true,
    "endpointCode": "NIDAGETIDINFO",
    "usePrefetch": true,
    "required": false,
    "defaultRequired": true,
    "placeholder": "Enter your National ID number",
    "populates": [
      { "valueKey": "surname", "targetKey": "LAST_NAME" },
      { "valueKey": "forename", "targetKey": "FIRST_NAME" },
      { "valueKey": "dateOfBirth", "targetKey": "DATE_OF_BIRTH" },
      { "valueKey": "sex", "targetKey": "GENDER" }
    ]
  },
  "expressions": {
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {
      "required": "This field is required.",
      "invalidId": "The ID number should be a valid Rwandan ID.",
      "invalidInput": "National ID must be 16 digits.",
      "invalidNidInput": "Invalid National ID number.",
      "verificationFailed": "ID verification failed. Please try again.",
      "verificationInvalid": "Details don't match NIDA records. Please check the ID owner's info and try again.",
      "verificationRequired": "Please verify that you have consent from the owner of the ID.",
      "applicantMustBeAlive": "The national ID should not belong to a deceased person.",
      "applicantMustBeAlive1": "The national ID should not belong to a deceased person.",
      "endpointCodeNotConfigured": "Missing endpoint code in ID Component."
    }
  },
  "validators": {
    "validation": [
      {
        "name": "genericUtilValidator",
        "options": {
          "prop1": ["options", "formState", "FETCHED_DATA", "APPLICANT_NID", "citizenStatus"],
          "prop2": "DEAD",
          "comparator": "!==",
          "validationName": "applicantMustBeAlive"
        }
      },
      {
        "name": "genericUtilValidator",
        "options": {
          "prop1": ["options", "formState", "FETCHED_DATA", "APPLICANT_NID", "citizenStatus"],
          "prop2": "DECEASED",
          "comparator": "!==",
          "validationName": "applicantMustBeAlive1"
        }
      }
    ]
  }
}

Child ID with age validation

{
  "key": "CHILD_ID_NUMBER",
  "type": "customidinput",
  "props": {
    "label": "Child ID",
    "idType": "CHILD_ID",
    "idLength": 8,
    "useBaseUrl": true,
    "endpointCode": "NIDAGETCHILDINFO",
    "usePrefetch": false,
    "required": false,
    "defaultRequired": true,
    "idConditions": {
      "ageLimit": {
        "key": "dateOfBirth",
        "maximumAge": 17
      }
    },
    "populates": [
      { "valueKey": "surname", "targetKey": "CHILD_LAST_NAME" },
      { "valueKey": "forename", "targetKey": "CHILD_FIRST_NAME" }
    ]
  },
  "expressions": {
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {
      "required": "This field is required.",
      "invalidId": "Please enter a valid Child ID.",
      "invalidInput": "Child ID must be 8 digits.",
      "verificationFailed": "ID verification failed. Please try again.",
      "verificationInvalid": "Details don't match any record.",
      "verificationRequired": "Please verify that you have consent from the ID owner.",
      "endpointCodeNotConfigured": "Missing endpoint code in ID Component.",
      "maximumAge": "The child must be under 18 years old."
    }
  },
  "validators": {
    "validation": ["maximumAge"]
  }
}

Auto-populated readonly field pattern

Fields that receive values from populates should be hidden until the value is fetched. The props.hideField expression combines the trigger condition AND the presence of the populated value.

{
  "key": "FIRST_NAME",
  "type": "input",
  "props": {
    "label": "First Name",
    "readonly": true,
    "required": false,
    "hideField": true,
    "defaultRequired": true
  },
  "expressions": {
    "props.hideField": "!(model?.APPLICANT_NID && model?.FIRST_NAME)",
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {
      "required": "This field is required."
    }
  }
}

The expression !(model?.NID_FIELD && model?.THIS_FIELD) shows the readonly field only when both the ID lookup has run and this field has a value.

Common mistakes

  • Omitting endpointCode for NID or CHILD_ID — the component locks as read-only at runtime.
  • Wrong idLength — NID is 16, CHILD_ID is 8, NIN is 10.
  • Setting populates as an object instead of an array — throws 'populates should be an array' at runtime.
  • Using wrong valueKey names — the real keys are surname and forename (not surnames, foreName). Mismatched keys silently fail.
  • Setting usePrefetch: true for FOREIGNER_ID or REFUGEE_ID — prefetch only works for NATIONAL_ID.
  • Setting nidType when idType is not "NID"nidType is meaningless for CHILD_ID and NIN.
  • Omitting useBaseUrl: true — the identity endpoint will not resolve through the API gateway.
  • Using customidinput for TIN numbers — use customtininput instead.

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 > customidinput
  • required: false is set (never true)
  • defaultRequired is set
  • expressions["props.required"] is present with the exact required expression
  • idType, idLength, and useBaseUrl: true are set
  • nidType is set when idType is "NID"
  • endpointCode is set for NID and CHILD_ID
  • usePrefetch is false for FOREIGNER_ID, REFUGEE_ID, CHILD_ID, and NIN
  • All validation messages are present (at minimum the 7 core ones)
  • populates is an array, and all targetKey values match real field keys in the form
  • Populated target fields are readonly: true with the combined hide expression
  • Liveness check validators added if the ID owner must be alive

On this page