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.
Instead of customidinput, use… |
For… |
|---|---|
input |
Plain text reference numbers with no external verification |
customtininput |
TIN (Tax Identification Number) — never use customidinput for TINs |
customphonenumber |
Phone numbers |
Every customidinput requires idType. For idType: "NID", nidType is also required and controls which NID prefix is accepted.
idType |
nidType |
idLength |
endpointCode |
usePrefetch |
|---|---|---|---|---|
NID |
NATIONAL_ID |
16 |
NIDAGETIDINFO |
true |
NID |
FOREIGNER_ID |
16 |
NIDAGETIDINFO |
false |
NID |
REFUGEE_ID |
16 |
NIDAGETIDINFO |
false |
CHILD_ID |
— | 8 |
NIDAGETCHILDINFO |
false |
NIN |
— | 10 |
not required | false |
| Prop | Type | Required? | Description |
|---|---|---|---|
label |
string |
required | Visible label. Must be unique across the form. |
required |
boolean |
required | Always false. The expression controls the runtime value. |
defaultRequired |
boolean |
required | true for required fields, false for optional ones. |
idType |
'NID' \| 'CHILD_ID' \| 'NIN' |
required | Document 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. |
idLength |
number |
required | Expected digit count. 16 for NID, 8 for CHILD_ID, 10 for NIN. |
useBaseUrl |
boolean |
required | Always true — prepends the API gateway base URL. |
endpointCode |
string |
required for NID and CHILD_ID | Integration endpoint code. Not required for NIN. |
usePrefetch |
boolean |
optional | true 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. |
populates |
array |
optional | { valueKey, targetKey } pairs mapping API response keys to form field keys. Must be an array, not an object. |
idConditions |
object |
optional | Age constraint applied after fetch. See below. |
placeholder |
string |
optional | Ghost text shown inside the field. |
readonly |
boolean |
optional | Renders the input non-editable. |
hint |
string |
optional | Help text shown below the field. |
tooltip |
string |
optional | Tooltip shown on hover. |
hideField |
boolean |
optional | Hides field and excludes its value. Toggle via expressions["props.hideField"]. |
idConditions.ageLimitEnforces 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.
populates.valueKey)idType: "NID")valueKey |
Description |
|---|---|
surname |
Family name |
forename |
Given name(s) |
fatherName |
Father's name |
motherName |
Mother's name |
dateOfBirth |
Date of birth |
sex |
Gender |
nationality |
Nationality |
countryOfBirth |
Country of birth |
placeOfBirth |
Place of birth |
civilStatus |
Civil / marital status |
citizenStatus |
Liveness — "ALIVE", "DEAD", or "DECEASED" |
idType: "CHILD_ID")valueKey |
Description |
|---|---|
surname |
Family name |
forename |
Given name(s) |
fatherName |
Father's name |
motherName |
Mother's name |
dateOfBirth |
Date of birth |
sex |
Gender |
countryOfBirth |
Country of birth |
placeOfBirth |
Place of birth |
civilStatus |
Civil / marital status |
| Key | When it fires |
|---|---|
required |
Field is empty and required |
invalidId |
ID does not pass format check |
invalidInput |
ID does not match expected idLength |
invalidNidInput |
ID is not a valid NID for the given nidType |
verificationFailed |
NIDA API call failed (network / server error) |
verificationInvalid |
ID not found in NIDA records |
verificationRequired |
User has not confirmed consent |
endpointCodeNotConfigured |
endpointCode is missing — field locks as read-only |
{
"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"
}
}
]
}
}
{
"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"]
}
}
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.
endpointCode for NID or CHILD_ID — the component locks as read-only at runtime.idLength — NID is 16, CHILD_ID is 8, NIN is 10.populates as an object instead of an array — throws 'populates should be an array' at runtime.valueKey names — the real keys are surname and forename (not surnames, foreName). Mismatched keys silently fail.usePrefetch: true for FOREIGNER_ID or REFUGEE_ID — prefetch only works for NATIONAL_ID.nidType when idType is not "NID" — nidType is meaningless for CHILD_ID and NIN.useBaseUrl: true — the identity endpoint will not resolve through the API gateway.customidinput for TIN numbers — use customtininput instead.key is UPPER_SNAKE_CASE and unique across the entire formprops.label is present, unique, and correctly casedsections > formly-group > block > customidinputrequired: false is set (never true)defaultRequired is setexpressions["props.required"] is present with the exact required expressionidType, idLength, and useBaseUrl: true are setnidType is set when idType is "NID"endpointCode is set for NID and CHILD_IDusePrefetch is false for FOREIGNER_ID, REFUGEE_ID, CHILD_ID, and NINpopulates is an array, and all targetKey values match real field keys in the formreadonly: true with the combined hide expression