Skip to main content

Conditional Logic in React Forms

Conditional logic is what turns a static form into a dynamic one. It lets you show, hide, or adapt fields based on what the user has already entered. In FormEngine, this behavior lives in the schema instead of in useState, watch, and conditional JSX branches. If you want dynamic React forms without a lot of component-level wiring, this page is the core reference.

How conditional logic works in FormEngine

The main mechanism is renderWhen. When a component has renderWhen, FormEngine checks the condition against the current form state and renders the component only when the result is true. This gives you a schema-driven way to build:
  • progressive disclosure
  • optional sections
  • dependent fields
  • dynamic wizard flows

Quick example

Show a company field only when the selected account type is business:
Conditional field
{
  "key": "companyName",
  "type": "RsInput",
  "props": {
    "label": { "value": "Company name" }
  },
  "renderWhen": {
    "value": "form.data.accountType === 'business'"
  }
}
That is the basic pattern. The condition lives in the schema, not in a React component branch.

Real working example from the FormEngine examples

The community SampleForm.json uses real conditional rendering to switch between success and error messages after validation:
Success and error visibility from SampleForm.json
[
  {
    "key": "errorMessage",
    "type": "RsStaticContent",
    "props": {
      "content": {
        "value": "Not all fields of the form are filled in correctly."
      }
    },
    "renderWhen": {
      "value": "false"
    }
  },
  {
    "key": "successMessage",
    "type": "RsStaticContent",
    "props": {
      "content": {
        "value": "The form has been sent, thank you!"
      }
    },
    "renderWhen": {
      "value": "false"
    }
  }
]
And the same example uses a real code action to flip those renderWhen values after the runtime validation result is known:
showValidationResult action from the same example
const setVisible = (key, visible) => {
  const componentStore = e.store.form.componentTree.findByKey(key)?.store
  if (componentStore) {
    componentStore.renderWhen = { value: visible }
  }
}

const hasErrors = e.store.form.componentTree.hasErrors
setVisible('errorMessage', hasErrors)
setVisible('successMessage', !hasErrors)
This is a strong real-world example because it shows conditional logic working with:
  • validation state
  • action chains
  • runtime component store updates
The visible result of that pattern looks like this in the old working example: Conditional logic example The screenshot above reflects the same dynamic pattern shown in the schema and action examples on this page.

What renderWhen can access

Conditions run with access to the form object:
PathWhat it provides
form.datacurrent form values
form.errorscurrent validation errors
form.hasErrorswhether the form has errors
form.stateshared workflow state
form.parentDataparent item data inside repeaters
form.rootDataroot-level form data
form.indexcurrent index inside repeaters
Most conditions only need form.data.

Expression-based conditions

Use renderWhen.value for short conditions:
Simple expression
{
  "renderWhen": {
    "value": "form.data.paymentMethod === 'card'"
  }
}
You can combine conditions too:
Combined condition
{
  "renderWhen": {
    "value": "form.data.accountType === 'business' && form.data.country === 'US'"
  }
}
Use expressions when the rule is short enough to stay readable.

Function-based conditions

For more complex logic, use computeType: "function" and fnSource:
Function-based condition
{
  "key": "discountCode",
  "type": "RsInput",
  "renderWhen": {
    "computeType": "function",
    "fnSource": "const total = Number(form.data.quantity || 0) * Number(form.data.price || 0)\nreturn total > 1000"
  }
}
Use this when:
  • the condition is too long for a one-line expression
  • you need calculations
  • multiple values must be checked together

Common patterns

Show a field from a checkbox

Checkbox-driven conditional field
{
  "key": "shippingAddress",
  "type": "RsInput",
  "props": {
    "label": { "value": "Shipping address" }
  },
  "renderWhen": {
    "value": "form.data.differentShipping === true"
  }
}

Show different fields from a selected option

Payment method switch
[
  {
    "key": "cardNumber",
    "type": "RsInput",
    "renderWhen": {
      "value": "form.data.paymentMethod === 'card'"
    }
  },
  {
    "key": "bankAccount",
    "type": "RsInput",
    "renderWhen": {
      "value": "form.data.paymentMethod === 'bank'"
    }
  }
]

Show help or warnings from validation state

Error-based helper content
{
  "key": "helpText",
  "type": "RsStaticContent",
  "props": {
    "content": { "value": "Please fix the errors above before continuing." }
  },
  "renderWhen": {
    "value": "form.hasErrors"
  }
}

Conditional logic and validation

This is one of the most important practical details: when a field is hidden by renderWhen, its validation rules do not block submission. That means you can safely make a conditionally visible field required without worrying that it will fail validation while hidden. Use this together with validation to build:
  • optional business sections
  • conditional billing fields
  • step-specific required fields
  • gated follow-up questions

What happens to hidden field values

By default, FormEngine preserves the last value of a field even when the field becomes hidden. That is often useful, but not always. If you want hidden values cleared, trigger a reset or update action from the controlling field and keep the data model explicit. Use actions and events when you need that level of control.

Conditional logic in the Designer

If your team uses the Designer, conditional logic can also be configured visually. That gives teams a path from dynamic schema rules to visual editing without changing the underlying model. See Designer conditional rendering for the builder-specific workflow.

FormEngine vs manual React conditional fields

The main difference is where the logic lives:
ApproachWhere conditions liveTypical cost
Manual React implementationcomponent state and conditional JSXmore wiring as the form grows
FormEngineJSON schema via renderWheneasier reuse and cleaner form definitions
This matters most when:
  • forms have many branching paths
  • fields depend on previous answers
  • the same workflow appears across multiple screens or products
  • teams want a visual builder later

FAQ

Yes. You can apply conditional logic to larger sections and step-like structures, not only to individual input fields.
Use expressions for short readable rules. Use functions when the condition needs calculations or would be too long in one line.
Yes. Hidden fields do not block submission through their validation rules.
Yes. For that pattern, combine conditional logic with computed properties or other schema-driven state control.

Next steps

Read validation

Combine conditional fields with schema-driven validation.

Use computed properties

Derive field values and UI state from other data.

Build a multi-step form

Apply conditional logic in a longer workflow.

Try it in the Online Builder

Configure dynamic field behavior visually.