Conditional Logic
Core Forms supports conditional field visibility and action execution using both a legacy attribute-based format and a structured JSON format. Conditions are evaluated on the frontend in real time and on the server side for security.
Frontend: Data Attributes
Show/Hide Attributes
Add data-show-if or data-hide-if attributes to any form element to control its visibility based on another field's value:
<!-- Show the company field only when "Business" is selected -->
<div data-show-if="account_type=Business">
<label for="company">Company Name</label>
<input type="text" name="company" id="company">
</div>
<!-- Hide the discount code field when "Free" plan is selected -->
<div data-hide-if="plan=Free">
<label for="discount_code">Discount Code</label>
<input type="text" name="discount_code" id="discount_code">
</div>
Legacy Format Syntax
The legacy format supports several matching patterns:
<!-- Exact match -->
<div data-show-if="role=Manager">
<!-- Multiple values (OR) separated by pipe -->
<div data-show-if="role:Manager|Director|VP">
<!-- Any non-empty value (wildcard) -->
<div data-show-if="company=*">
<!-- Exact match with equals sign -->
<div data-hide-if="newsletter=no">
Format rules:
| Pattern | Meaning |
|---|---|
field=value |
Show/hide when field equals value |
field:val1\|val2\|val3 |
Show/hide when field matches any listed value |
field=* |
Show/hide when field has any non-empty value |
Hidden fields are excluded from submission data and validation. When a field is hidden by conditional logic, its required attribute is temporarily removed.
Structured JSON Format
For complex conditions, use the structured format in your form schema. This supports 14 operators, grouped conditions, and nested logic.
Basic Condition
{
"conditions": {
"action": "show",
"rules": [
{ "field": "account_type", "operator": "=", "value": "Business" }
]
}
}
Supported Operators
| Operator | Description | Example Value |
|---|---|---|
= |
Equals | "Business" |
!= |
Not equals | "Free" |
> |
Greater than | 100 |
< |
Less than | 50 |
>= |
Greater than or equal | 18 |
<= |
Less than or equal | 65 |
contains |
String contains substring | "gmail" |
not_contains |
String does not contain | "test" |
starts_with |
String starts with | "Dr." |
ends_with |
String ends with | "@company.com" |
is_empty |
Field is empty | (no value needed) |
is_not_empty |
Field is not empty | (no value needed) |
in |
Value is in list | ["red", "blue", "green"] |
not_in |
Value is not in list | ["spam", "test"] |
Grouped Conditions: AND / OR Logic
Use the match property to control how multiple rules are combined:
{
"conditions": {
"action": "show",
"match": "all",
"rules": [
{ "field": "age", "operator": ">=", "value": 18 },
{ "field": "country", "operator": "=", "value": "US" }
]
}
}
"match": "all"-- all rules must be true (AND logic). This is the default."match": "any"-- at least one rule must be true (OR logic).
Nested Groups
For complex logic like "(A AND B) OR (C AND D)", nest condition groups:
{
"conditions": {
"action": "show",
"match": "any",
"rules": [
{
"match": "all",
"rules": [
{ "field": "role", "operator": "=", "value": "Manager" },
{ "field": "department", "operator": "=", "value": "Engineering" }
]
},
{
"match": "all",
"rules": [
{ "field": "role", "operator": "=", "value": "Director" },
{ "field": "department", "operator": "in", "value": ["Engineering", "Product"] }
]
}
]
}
}
This shows the field when the user is either an Engineering Manager or a Director in Engineering or Product.
Server-Side Evaluation
The ConditionEvaluator class handles server-side condition checks. This is critical for security -- frontend conditions can be bypassed, so the server re-evaluates all conditions during form processing.
ConditionEvaluator Class
use Core_Forms\ConditionEvaluator;
// Evaluate a single condition
$evaluator = new ConditionEvaluator();
$result = $evaluator->evaluate([
'field' => 'account_type',
'operator' => '=',
'value' => 'Business',
], $submission_data);
// Returns: true or false
// Evaluate a condition group
$result = $evaluator->evaluate_group([
'match' => 'all',
'rules' => [
['field' => 'age', 'operator' => '>=', 'value' => 18],
['field' => 'country', 'operator' => '=', 'value' => 'US'],
],
], $submission_data);
Used in Action Conditions
The same ConditionEvaluator powers conditional actions (emails, webhooks, etc.). You can configure an action to only fire when certain conditions are met:
{
"actions": [
{
"type": "email",
"to": "sales@example.com",
"subject": "New Enterprise Lead",
"conditions": {
"match": "all",
"rules": [
{ "field": "plan", "operator": "=", "value": "Enterprise" },
{ "field": "team_size", "operator": ">", "value": 50 }
]
}
},
{
"type": "email",
"to": "support@example.com",
"subject": "New Free Signup",
"conditions": {
"match": "all",
"rules": [
{ "field": "plan", "operator": "=", "value": "Free" }
]
}
}
]
}
In this example, the sales team only receives email for Enterprise leads with 50+ team members, while support gets notified for Free signups.
Builder UI: Conditions Section
In the React visual builder, select a field, expand Conditions, and click + Add Condition. Each condition has an Action (Show if or Hide if) and a text Rule, such as account_type:Business. These controls generate the legacy attribute rules described above.
The older visual editor, identified by its Done button, does not have a Conditions control. Switch to Code and add data-show-if or data-hide-if to the field wrapper.
Neither inspector provides an AND/OR group editor, operator picker, or Add Group button. Use the structured JSON format through the schema API for grouped conditions; it is not generated by the inspector.
Examples
Dependent Dropdowns
Show a city dropdown based on the selected state:
<select name="state" id="state">
<option value="">Select State</option>
<option value="CA">California</option>
<option value="NY">New York</option>
</select>
<div data-show-if="state=CA">
<select name="city" id="city_ca">
<option value="LA">Los Angeles</option>
<option value="SF">San Francisco</option>
</select>
</div>
<div data-show-if="state=NY">
<select name="city" id="city_ny">
<option value="NYC">New York City</option>
<option value="BUF">Buffalo</option>
</select>
</div>
Conditional Required Fields
When a field becomes visible via conditions, you often want it to be required only when shown:
<div data-show-if="has_referral=yes">
<label for="referral_code">Referral Code <span class="required">*</span></label>
<input type="text" name="referral_code" id="referral_code" required>
</div>
When has_referral is not "yes", the wrapper is hidden, required is removed from the input, and the field is excluded from validation.
Structured Format: Survey Branching
{
"fields": [
{
"name": "satisfaction",
"type": "radio",
"label": "How satisfied are you?",
"options": ["Very Satisfied", "Satisfied", "Neutral", "Dissatisfied", "Very Dissatisfied"]
},
{
"name": "what_went_well",
"type": "textarea",
"label": "What did you enjoy most?",
"conditions": {
"action": "show",
"rules": [
{ "field": "satisfaction", "operator": "in", "value": ["Very Satisfied", "Satisfied"] }
]
}
},
{
"name": "what_to_improve",
"type": "textarea",
"label": "What could we improve?",
"conditions": {
"action": "show",
"rules": [
{ "field": "satisfaction", "operator": "in", "value": ["Dissatisfied", "Very Dissatisfied"] }
]
}
}
]
}
This shows different follow-up questions depending on the user's satisfaction rating.