Components
textarea
Multi-line text field. Use for free-text answers where the user may write several sentences.
A multi-line text field. Use for free-text answers where the user may write several sentences.
Read Form Rules before using this component — keys, labels, required fields, expressions, visibility, and validation all follow shared conventions.
When to use
- Remarks, descriptions, justifications, explanations
- Long addresses or multi-line narrative answers
- Any free-text answer that doesn't fit on a single line
When NOT to use
Instead of textarea, use… | For… |
|---|---|
input | Single-line free-text (names, references, URLs) |
customphonenumber | Phone numbers |
customcurrencyformatinput | Currency / monetary amounts |
customidinput | National IDs and document numbers |
Props
| Prop | Type | Required? | Description |
|---|---|---|---|
label | string | required | Visible label. Title Case for nouns ("Project Description"), Sentence case for questions ("Why are you applying?"). Must be unique across the form. |
required | boolean | required | Always false. The expression controls the runtime value — never set this to true directly. |
defaultRequired | boolean | required | true for required fields, false for optional ones. This is the value the expression reads. |
rows | number | optional | Visible row height. Always set explicitly; use at least 3. The default 1 renders a single-line box. |
cols | number | optional | Column width of the textarea element. |
placeholder | string | optional | Ghost text shown inside the field before the user types. |
tooltip | string | optional | Short help text shown as an icon tooltip next to the label. |
hint | string | optional | Subtle help text rendered below the field, always visible. Can be driven dynamically via expressions["props.hint"]. |
readonly | boolean | optional | Prevents editing. Use expressions["props.readonly"] to toggle dynamically. Do not use disabled. |
hideField | boolean | optional | Hides the field and excludes its value from submission. Use expressions["props.hideField"] to toggle. Do not use hide directly. |
maxLength | number | optional | Maximum character count. Requires a validation.messages.maxLength entry. |
minLength | number | optional | Minimum character count. Requires a validation.messages.minLength entry. |
The required mechanism
Every textarea field must include this exact expression, regardless of whether the field is required or optional. Never omit it, never change it.
"expressions": {
"props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
}The expression reads defaultRequired and automatically becomes false when the field is hidden — preventing hidden fields from blocking form submission.
- To make a field required: set
defaultRequired: true. - To make a field optional: set
defaultRequired: false.
Examples
Required multi-line description
{
"key": "PROJECT_DESCRIPTION",
"type": "textarea",
"props": {
"label": "Project Description",
"required": false,
"defaultRequired": true,
"rows": 4,
"placeholder": "Enter project description"
},
"expressions": {
"props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
},
"validation": {
"messages": {
"required": "Project Description is required."
}
}
}Optional remarks field with maxLength
{
"key": "ADDITIONAL_REMARKS",
"type": "textarea",
"props": {
"label": "Additional Remarks",
"required": false,
"defaultRequired": false,
"rows": 3,
"maxLength": 500,
"placeholder": "Optional notes"
},
"expressions": {
"props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
},
"validation": {
"messages": {
"required": "Additional Remarks is required.",
"maxLength": "Additional Remarks must be 500 characters or fewer."
}
}
}Complaint description with explicit rows
{
"key": "COMPLAINT_DESCRIPTION",
"type": "textarea",
"props": {
"label": "Complaint Description",
"required": false,
"defaultRequired": true,
"rows": 3,
"cols": 1,
"placeholder": "Enter complaint description"
},
"expressions": {
"props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
},
"validation": {
"messages": {
"required": "Complaint Description is required."
}
}
}Checklist
-
keyisUPPER_SNAKE_CASEand unique across the entire form -
props.labelis present, unique, and correctly cased - Field is nested at the correct depth:
sections > formly-group > block > textarea -
required: falseis set (nevertrue) -
defaultRequiredis set (trueorfalse) -
expressions["props.required"]is present with the exact required expression -
props.rowsis set explicitly to3or more — never rely on the default -
validation.messages.requiredis present -
validation.messageshas an entry for every constrained prop (maxLength,minLength) - Not using
textareafor single-line values (see "When NOT to use")