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…
inputSingle-line free-text (names, references, URLs)
customphonenumberPhone numbers
customcurrencyformatinputCurrency / monetary amounts
customidinputNational IDs and document numbers

Props

PropTypeRequired?Description
labelstringrequiredVisible label. Title Case for nouns ("Project Description"), Sentence case for questions ("Why are you applying?"). Must be unique across the form.
requiredbooleanrequiredAlways false. The expression controls the runtime value — never set this to true directly.
defaultRequiredbooleanrequiredtrue for required fields, false for optional ones. This is the value the expression reads.
rowsnumberoptionalVisible row height. Always set explicitly; use at least 3. The default 1 renders a single-line box.
colsnumberoptionalColumn width of the textarea element.
placeholderstringoptionalGhost text shown inside the field before the user types.
tooltipstringoptionalShort help text shown as an icon tooltip next to the label.
hintstringoptionalSubtle help text rendered below the field, always visible. Can be driven dynamically via expressions["props.hint"].
readonlybooleanoptionalPrevents editing. Use expressions["props.readonly"] to toggle dynamically. Do not use disabled.
hideFieldbooleanoptionalHides the field and excludes its value from submission. Use expressions["props.hideField"] to toggle. Do not use hide directly.
maxLengthnumberoptionalMaximum character count. Requires a validation.messages.maxLength entry.
minLengthnumberoptionalMinimum 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

  • 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 > textarea
  • required: false is set (never true)
  • defaultRequired is set (true or false)
  • expressions["props.required"] is present with the exact required expression
  • props.rows is set explicitly to 3 or more — never rely on the default
  • validation.messages.required is present
  • validation.messages has an entry for every constrained prop (maxLength, minLength)
  • Not using textarea for single-line values (see "When NOT to use")

On this page