Conditional Logic
Forma uses FEEL expressions to control dynamic field behavior. Three properties control when fields are visible, required, or editable.
Test complex expressions with simple field values first, then add conditions incrementally.
Properties
| Property | Description | Default |
|---|---|---|
visibleWhen | Show field when expression is true | Always visible |
requiredWhen | Require field when expression is true | Uses schema required |
enabledWhen | Allow editing when expression is true | Always enabled |
readonlyWhen | Make field read-only when expression is true | Always editable |
visibleWhen
Control when a field is displayed:
{
"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:
{
"insuranceNumber": {
"label": "Insurance Number",
"visibleWhen": "hasInsurance = true",
"requiredWhen": "hasInsurance = true"
}
}
Priority
requiredWhenoverrides the schema'srequiredarray- If both schema
requiredandrequiredWhenare set,requiredWhentakes 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:
{
"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:
{
"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
| Operator | Description | Example |
|---|---|---|
= | Equal | status = "active" |
!= | Not equal | status != "archived" |
> | Greater than | age > 18 |
>= | Greater or equal | age >= 21 |
< | Less than | price < 100 |
<= | Less or equal | price <= 50 |
Logical Operators
| Operator | Description | Example |
|---|---|---|
and | Both conditions true | age >= 18 and hasLicense = true |
or | Either condition true | status = "active" or status = "pending" |
not | Negation | not(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\""
}
}