Skip to main content

Conditional Logic

eSheet supports conditional rules that control field visibility, enabled state, and required state based on other field values or custom expressions.

How Rules Work​

Each field can have an optional rules array. Each rule defines:

  1. Effect -- What happens when the rule evaluates to true
  2. Logic mode -- How multiple conditions within the rule are combined
  3. Conditions -- One or more conditions to evaluate
interface ConditionalRule {
effect: 'visible' | 'enable' | 'required';
logic: 'AND' | 'OR';
conditions: Condition[];
}

Effects​

EffectBehavior when rule is trueDefault (no rules)
visibleField is shownVisible
enableField is interactive (not grayed out)Enabled
requiredField must be answeredBased on required prop

Logic Modes​

ModeBehavior
ANDAll conditions must be true
ORAny condition being true is sufficient

Multiple Rules​

When a field has multiple rules with the same effect, they combine with OR semantics -- if any rule evaluates to true, the effect is applied.

Option-Scoped Visibility​

Rules can also be placed on an individual option. A rule inside field.rules affects the field; a rule inside field.options[n].rules affects only that option. In both cases, condition.targetId identifies the source field whose response is evaluated.

Option rules use the existing ConditionalRule shape, but only the visible effect applies:

id: incidentLocation
fieldType: dropdown
question: Incident location
options:
- id: houston-hq
value: Houston HQ
rules:
- effect: visible
logic: AND
conditions:
- conditionType: field
targetId: incidentCountry
operator: equals
expected: us

Here, incidentLocation owns the option, houston-hq is the affected option, and incidentCountry is the controlling field. Options without a matching visible rule remain visible. Hidden selected options remain in the response and produce a hard availability validation error.

Condition Types​

Field Conditions​

Compare a target field's response against an expected value:

interface Condition {
conditionType: 'field';
targetId: string; // Field ID to evaluate
operator: ConditionOperator;
expected?: string; // Value to compare against
propertyAccessor?: string; // Optional: 'length', 'count'
}

Expression Conditions​

Evaluate a custom JavaScript-like expression using eSheet's safe evaluator. No new Function — works even when dangerous JS is disabled.

interface Condition {
conditionType: 'expression';
expression: string; // e.g. '{fieldA} + {fieldB} > 100'
}

JS Conditions​

Evaluate arbitrary JavaScript. Requires both the host and schema to opt in via allowDangerousJS and dangerouslyAllowJS. When not opted in, JS conditions evaluate as false.

interface Condition {
conditionType: 'js';
expression: string; // arbitrary JS, receives `responses` argument
}

See Dangerous JS for full setup requirements and security guidance.

Operators​

OperatorDescriptionWorks with
equalsExact matchText, selection value
notEqualsNot equalText, selection value
containsWord-boundary match (whole words, case-insensitive)Text answers
includesArray includes valueMulti-select (check, ranking)
emptyField has no answerAll field types
notEmptyField has an answerAll field types
greaterThanNumeric greater thanNumeric text, rating values
greaterThanOrEqualNumeric >=Numeric text, rating values
lessThanNumeric less thanNumeric text, rating values
lessThanOrEqualNumeric <=Numeric text, rating values

:::note contains behaviour contains matches on word boundaries, not arbitrary substrings. "one two" will match "one two three" but not "onetwo". Use an expression condition for arbitrary substring matching. :::

Property Accessors​

Access a specific property of the target field's response before comparing:

AccessorDescriptionExample use
lengthLength of text answer or arrayCheck if multi-select has >= 3 selections
countNumber of selected itemsSame as length for arrays
conditionType: field
targetId: symptoms
propertyAccessor: length
operator: greaterThanOrEqual
expected: '3'

Expression Syntax Reference​

Expression conditions (conditionType: 'expression') support a JavaScript-like syntax for complex logic.

Field References​

Use {fieldId} to reference a field's answer value:

conditionType: expression
expression: '{weight} > 100'

Property Accessors in Expressions​

Access properties on field values:

  • {fieldId}.length — Length of text or array
  • {fieldId}.count — Number of selected items (alias for length)
conditionType: expression
expression: '{symptoms}.length >= 3'

Supported Operators​

CategoryOperatorsExample
Comparison==, !=, >, >=, <, <={age} >= 18
Strict equality===, !=={status} === "active"
Logical&&, ||{a} > 0 && {b} > 0
Negation!!{hasAllergies}
Arithmetic+, -, *, /, %{weight} / ({height} * {height})
Grouping()({a} + {b}) * 2

Literal Values​

  • Numbers: 123, 3.14, -5
  • Strings: "text" or 'text'
  • Booleans: true, false
  • Null: null

Complex Expression Examples​

BMI calculation check:

conditionType: expression
expression: '{weight} / (({height}/100) * ({height}/100)) > 25'

Multiple field check:

conditionType: expression
expression: '{field1} > 0 && {field2} > 0 && {field3} != null'

String comparison:

conditionType: expression
expression: "{status} == 'approved' || {override} == true"

Examples​

Show a field when a specific option is selected​

Show "Other reason" text field when the user selects "Other" in a radio:

id: other_reason
fieldType: text
question: Please specify
inputType: string
rules:
- effect: visible
logic: AND
conditions:
- conditionType: field
targetId: reason
operator: equals
expected: Other

Make a field required based on another answer​

Require email when the user answers "Yes" to receiving updates:

id: email
fieldType: text
question: Email Address
inputType: email
rules:
- effect: required
logic: AND
conditions:
- conditionType: field
targetId: wants_updates
operator: equals
expected: 'Yes'

Show field when ANY of multiple conditions are met (OR)​

Show follow-up when ANY high-severity symptom is reported:

id: followup
fieldType: longtext
question: Please describe your symptoms in detail
rules:
- effect: visible
logic: OR
conditions:
- conditionType: field
targetId: headache_severity
operator: equals
expected: Severe
- conditionType: field
targetId: back_pain_severity
operator: equals
expected: Severe

Enable based on numeric comparison​

Enable a section only when the patient's age is 18 or older:

id: adult_section
fieldType: section
title: Adult Health History
rules:
- effect: enable
logic: AND
conditions:
- conditionType: field
targetId: age
operator: greaterThanOrEqual
expected: '18'
fields:
- id: smoker
fieldType: boolean
question: Do you smoke?

Expression-based condition​

Show a BMI result field only when both weight and height have been filled:

id: bmi_display
fieldType: display
content: 'Your BMI is: *<{weight} / (({height}/100) * ({height}/100))>*'
rules:
- effect: visible
logic: AND
conditions:
- conditionType: expression
expression: '{weight} > 0 && {height} > 0'

Multiple conditions with AND logic​

Show a field only when BOTH conditions are met:

rules:
- effect: visible
logic: AND
conditions:
- conditionType: field
targetId: has_insurance
operator: equals
expected: 'Yes'
- conditionType: field
targetId: insurance_type
operator: notEquals
expected: Medicare

How Rules Are Evaluated​

  1. For each field, eSheet checks all rules matching the requested effect (visible, enable, or required)
  2. Within a rule, conditions are combined with the rule's logic mode (AND or OR)
  3. When multiple rules target the same effect, they use OR semantics -- if any rule passes, the effect is applied
  4. Hidden fields (visibility = false) are excluded from validation
  5. Disabled fields are excluded from validation
  6. Rules are evaluated in real-time as users fill out the form
  7. conditionType: 'js' evaluates as false when dangerous JS is not enabled — see Dangerous JS