FEEL Function Reference
Forma uses FEEL (Friendly Enough Expression Language) for dynamic expressions. This page provides a complete reference of available functions and operators.
Bookmark this page as a quick reference while building forms. Use the table of contents on the right to jump to specific functions.
Context Variables
In FEEL expressions, you can access form data using these patterns:
| Pattern | Description | Example |
|---|---|---|
fieldName | Direct field access | age >= 18 |
computed.name | Computed field value | computed.bmi > 25 |
ref.path | Reference data lookup | ref.taxRates.CA |
value | Current field value (in validation) | value >= 0 |
matrixField.rowId | Matrix row value (dot notation) | service_rating.speed >= 3 |
item.fieldName | Array item field (in array context) | item.quantity > 0 |
itemIndex | Array item index (0-based) | itemIndex = 0 |
Operators
Arithmetic
| Operator | Description | Example |
|---|---|---|
+ | Addition | price + tax |
- | Subtraction | total - discount |
* | Multiplication | quantity * unitPrice |
/ | Division | total / count |
** | Exponentiation | base ** 2 |
Comparison
| 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
| Operator | Description | Example |
|---|---|---|
and | Both conditions true | age >= 18 and hasLicense |
or | Either condition true | status = "active" or status = "pending" |
not | Negation | not(isBlocked) |
String Functions
string length
Returns the length of a string.
{
"rule": "string length(value) >= 3",
"message": "Must be at least 3 characters"
}
substring
Extracts a portion of a string.
substring(string, start)
substring(string, start, length)
{
"expression": "substring(phone, 1, 3)"
}
Note: FEEL uses 1-based indexing for strings.
upper case / lower case
Convert string case.
{
"expression": "upper case(code)",
"expression": "lower case(email)"
}
contains
Check if a string contains a substring.
{
"visibleWhen": "contains(email, \"@company.com\")"
}
starts with / ends with
Check string prefix or suffix.
{
"visibleWhen": "starts with(phone, \"+1\")"
}
{
"visibleWhen": "ends with(email, \".edu\")"
}
matches
Test a string against a regular expression pattern.
{
"rule": "matches(value, \"^[A-Z]{2}[0-9]{4}$\")",
"message": "Must be 2 letters followed by 4 digits (e.g., AB1234)"
}
String Concatenation
Use + to concatenate strings.
{
"expression": "firstName + \" \" + lastName"
}
Numeric Functions
abs
Returns the absolute value.
{
"expression": "abs(difference)"
}
floor / ceiling
Round down or up to nearest integer.
{
"expression": "floor(price)",
"expression": "ceiling(quantity)"
}
round
Round to specified precision.
round(number)
round(number, scale)
{
"expression": "round(total, 2)"
}
min / max
Find minimum or maximum in a list.
{
"expression": "min([price1, price2, price3])",
"expression": "max([score1, score2])"
}
sum
Sum all values in a list.
{
"expression": "sum([item1, item2, item3])"
}
mean
Calculate the average of a list.
{
"expression": "mean([score1, score2, score3])"
}
Date Functions
today
Returns the current date.
{
"rule": "date(value) > today()",
"message": "Date must be in the future"
}
now
Returns the current datetime.
{
"rule": "date and time(value) < now()",
"message": "Must be a past datetime"
}
date
Parses a string into a date.
{
"expression": "date(dateOfBirth)",
"rule": "date(endDate) > date(startDate)"
}
Date Components
Extract parts from a date.
{
"expression": "year(date(dateOfBirth))",
"expression": "month(date(startDate))",
"expression": "day(date(endDate))"
}
Date Arithmetic
Subtract dates to get duration.
{
"expression": "date(endDate) - date(startDate)"
}
List Functions
count
Returns the number of items in a list.
{
"visibleWhen": "count(selectedItems) > 0"
}
all / any
Check if all or any items match a condition.
{
"rule": "all items in items satisfy item.quantity > 0",
"message": "All items must have positive quantity"
}
append
Add an item to a list.
{
"expression": "append(existingList, newItem)"
}
flatten
Flatten nested lists.
{
"expression": "flatten([[1, 2], [3, 4]])"
}
Reference Data Functions
get value
Dynamic lookup in reference data using a field value as the key.
{
"referenceData": {
"taxRates": {
"CA": 0.0725,
"NY": 0.08,
"TX": 0.0625
}
},
"computed": {
"stateTax": {
"expression": "get value(ref.taxRates, state)"
}
}
}
Static Path Access
For fixed paths, use dot notation.
{
"expression": "ref.constants.taxRate"
}
Nested Lookup
Access nested properties from dynamic lookups.
{
"referenceData": {
"products": {
"SKU001": { "price": 9.99, "weight": 0.5 },
"SKU002": { "price": 19.99, "weight": 1.2 }
}
},
"computed": {
"productPrice": {
"expression": "get value(ref.products, selectedSku).price"
}
}
}
Conditional Expressions
if-then-else
Basic conditional.
{
"expression": "if age >= 18 then \"adult\" else \"minor\""
}
Chained conditions
{
"expression": "if score >= 90 then \"A\" else if score >= 80 then \"B\" else if score >= 70 then \"C\" else \"F\""
}
Null Handling
Null Check
{
"visibleWhen": "email != null"
}
Safe Operations
Handle null values with conditionals.
{
"expression": "if quantity != null then quantity * price else 0"
}
Null Coalescing
{
"expression": "if discountRate = null then 0 else discountRate"
}
Common Patterns
Age Calculation
{
"expression": "year(today()) - year(date(dateOfBirth))"
}
Percentage Calculation
{
"expression": "round((completed / total) * 100, 1)"
}
Conditional Discount
{
"expression": "if subtotal >= 100 then subtotal * 0.9 else subtotal"
}
Status Based on Value
{
"expression": "if computed.bmi < 18.5 then \"Underweight\" else if computed.bmi < 25 then \"Normal\" else if computed.bmi < 30 then \"Overweight\" else \"Obese\""
}
Expression Debugging
If your expression isn't working as expected:
- Check field names - Ensure exact spelling match
- Verify data types - Numbers and strings behave differently
- Handle nulls - Unset fields return null
- Test incrementally - Start simple and add complexity
Common Errors
| Error | Cause | Solution |
|---|---|---|
| Expression returns null | Field value is null | Add null check |
| Type mismatch | Comparing number to string | Use consistent types |
| Field not found | Typo in field name | Check field exists in schema |
| Syntax error | Invalid FEEL syntax | Check quotes and operators |