Skip to main content

Conditional Logic

Forma uses FEEL expressions to control dynamic field behavior. Three properties control when fields are visible, required, or editable.

tip

Test complex expressions with simple field values first, then add conditions incrementally.

Properties​

PropertyDescriptionDefault
visibleWhenShow field when expression is trueAlways visible
requiredWhenRequire field when expression is trueUses schema required
enabledWhenAllow editing when expression is trueAlways enabled
readonlyWhenMake field read-only when expression is trueAlways editable

visibleWhen​

Control when a field is displayed:

visible-when.json
{
"dependentField": {
"label": "Dependent Field",
"visibleWhen": "triggerField = true"
}
}

Examples​

Show based on checkbox:

{
"visibleWhen": "hasInsurance = true"
}

Show based on selection:

{
"visibleWhen": "country = \"US\""
}

Show based on number:

{
"visibleWhen": "age >= 18"
}

Show based on multiple conditions:

{
"visibleWhen": "hasInsurance = true and insuranceType = \"health\""
}

Hidden Field Behavior​

  • Hidden fields are not validated
  • Hidden fields retain their values (not cleared)
  • Hidden fields are excluded from submission if not visible

requiredWhen​

Make a field conditionally required:

required-when.json
{
"insuranceNumber": {
"label": "Insurance Number",
"visibleWhen": "hasInsurance = true",
"requiredWhen": "hasInsurance = true"
}
}

Priority​

  • requiredWhen overrides the schema's required array
  • If both schema required and requiredWhen are set, requiredWhen takes precedence

Examples​

Required based on selection:

{
"requiredWhen": "paymentMethod = \"credit_card\""
}

Required based on checkbox:

{
"requiredWhen": "needsShipping = true"
}

enabledWhen​

Control when a field can be edited:

enabled-when.json
{
"approvedBy": {
"label": "Approved By",
"enabledWhen": "status = \"pending\""
}
}

Disabled fields:

  • Are visible but grayed out
  • Cannot be edited by the user
  • Retain their existing value

Examples​

Disable after submission:

{
"enabledWhen": "submissionStatus != \"submitted\""
}

Enable only for specific users:

{
"enabledWhen": "userRole = \"admin\""
}

readonlyWhen​

Make a field conditionally read-only:

readonly-when.json
{
"invoiceNumber": {
"label": "Invoice Number",
"readonlyWhen": "status = \"approved\""
}
}

Readonly fields differ from disabled fields (enabledWhen: false):

  • Readonly: Visible and focusable, values are submitted, but the field cannot be edited
  • Disabled: Field appears greyed out and cannot be interacted with

Examples​

Read-only after approval:

{
"readonlyWhen": "approvalStatus = \"approved\""
}

Read-only for non-admins:

{
"readonlyWhen": "userRole != \"admin\""
}

FEEL Expression Syntax​

Comparison Operators​

OperatorDescriptionExample
=Equalstatus = "active"
!=Not equalstatus != "archived"
>Greater thanage > 18
>=Greater or equalage >= 21
<Less thanprice < 100
<=Less or equalprice <= 50

Logical Operators​

OperatorDescriptionExample
andBoth conditions trueage >= 18 and hasLicense = true
orEither condition truestatus = "active" or status = "pending"
notNegationnot(isBlocked)

String Values​

Strings must be quoted with escaped quotes:

{
"visibleWhen": "country = \"US\""
}

Null Checks​

{
"visibleWhen": "email != null"
}

Referencing Other Fields​

Reference fields directly by name:

{
"visibleWhen": "firstName != null and lastName != null"
}

Referencing Computed Values​

Use the computed. prefix:

{
"visibleWhen": "computed.total > 1000"
}

Common Patterns​

Show Additional Fields​

{
"otherReason": {
"label": "Please specify",
"visibleWhen": "reason = \"other\""
}
}

Conditional Sections​

Group related fields with the same condition:

{
"companyName": {
"label": "Company Name",
"visibleWhen": "customerType = \"business\""
},
"taxId": {
"label": "Tax ID",
"visibleWhen": "customerType = \"business\""
}
}

Progressive Disclosure​

Reveal fields as users complete previous ones:

{
"step2Field": {
"visibleWhen": "step1Field != null"
},
"step3Field": {
"visibleWhen": "step2Field != null"
}
}

Matrix-Dependent Fields​

Show or require fields based on matrix row values using dot notation:

{
"support_details": {
"label": "What could we improve?",
"type": "textarea",
"visibleWhen": "service_rating.support <= 2"
},
"follow_up_contact": {
"label": "May we contact you?",
"requiredWhen": "service_rating.quality <= 2 or service_rating.speed <= 2"
}
}

Mutual Exclusion​

Show one field OR another:

{
"phoneNumber": {
"visibleWhen": "contactMethod = \"phone\""
},
"emailAddress": {
"visibleWhen": "contactMethod = \"email\""
}
}