Components

input

Single-line text field. Use for free-text answers where the user types a value directly.

A single-line text field. Use for free-text answers where the user types a value directly.

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

When to use

  • Free-text: names, addresses, descriptions, URLs, reference numbers
  • Email addresses (type: "email")
  • Passwords (type: "password")

When NOT to use

Instead of input, use…For…
customphonenumberPhone numbers — never input with type: "tel"
customcurrencyformatinputCurrency / monetary amounts — never input with type: "number"
customidinputNational IDs and document numbers
numberPlain numeric inputs
textareaMulti-line text

Props

PropTypeRequired?Description
labelstringrequiredVisible label. Title Case for nouns ("First Name"), Sentence case for questions ("What is your occupation?"). 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.
typestringoptionalInput mode. One of: text (default), email, password, number, tel.
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.
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.
patternstringoptionalRegex the value must match. Requires a validation.messages.pattern entry. Write the raw regex string — no / delimiters.

The required mechanism

Every input 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 text field

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

Optional field with pattern validation

defaultRequired: false makes the field optional. The pattern prop adds format validation — a matching validation.messages.pattern entry is required whenever pattern is set.

{
  "key": "WEBSITE",
  "type": "input",
  "props": {
    "label": "Website",
    "required": false,
    "defaultRequired": false,
    "placeholder": "https://example.com",
    "pattern": "^https?://.+"
  },
  "expressions": {
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {
      "required": "Website is required.",
      "pattern": "Please enter a valid URL starting with http:// or https://"
    }
  }
}

Email field

{
  "key": "EMAIL_ADDRESS",
  "type": "input",
  "props": {
    "label": "Email Address",
    "required": false,
    "defaultRequired": true,
    "type": "email"
  },
  "expressions": {
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {
      "required": "Email Address 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 > input
  • required: false is set (never true)
  • defaultRequired is set (true or false)
  • expressions["props.required"] is present with the exact required expression
  • validation.messages.required is present
  • validation.messages has an entry for every constrained prop (pattern, maxLength, minLength)
  • type is one of the allowed values — not invented
  • Not using input for phone numbers, currency, IDs, or multi-line text (see "When NOT to use")

On this page