Advanced Features
Dynamic Hide
Dynamic field hiding allows you to show or hide fields based on the values of other fields. NovaForms provides two ways to implement dynamic hiding: field-level conditions and rule-based attribute effects.
Overview
There are two approaches to dynamic field hiding in NovaForms:
- Field Conditions: Direct field-level logic using
conditions.hiddenWhen - Rule Effects: Top-level rules that modify field attributes using
prop: "hidden"
Method 1: Field Conditions
Field conditions provide a direct way to hide fields based on other field values.
Basic Syntax
{
name: "fieldName",
type: "string",
conditions: {
hiddenWhen: [
{ field: "otherField", when: "equal", value: "hide" }
],
hiddenMode: "any" // or "all"
}
}
Simple Examples
Hide field when another field equals a value
const fields = [
{
name: "contactMethod",
type: "select",
title: "Preferred Contact Method",
options: [
{ value: "email", label: "Email" },
{ value: "phone", label: "Phone" }
]
},
{
name: "phone",
type: "tel",
title: "Phone Number",
conditions: {
hiddenWhen: [
{ field: "contactMethod", when: "equal", value: "email" }
]
}
}
];
Hide field when another field is empty
const fields = [
{
name: "hasAddress",
type: "boolean",
title: "Do you have a mailing address?"
},
{
name: "street",
type: "string",
title: "Street Address",
conditions: {
hiddenWhen: [
{ field: "hasAddress", when: "equal", value: false }
]
}
}
];
Hide field when another field is not empty
const fields = [
{
name: "email",
type: "email",
title: "Email Address"
},
{
name: "alternativeEmail",
type: "email",
title: "Alternative Email",
conditions: {
hiddenWhen: [
{ field: "email", when: "not empty" }
]
}
}
];
Complex Examples
Multiple conditions with AND logic
const fields = [
{
name: "orderTotal",
type: "number",
title: "Order Total"
},
{
name: "customerType",
type: "select",
title: "Customer Type",
options: [
{ value: "regular", label: "Regular" },
{ value: "premium", label: "Premium" }
]
},
{
name: "discount",
type: "number",
title: "Discount Amount",
conditions: {
hiddenWhen: [
{ field: "orderTotal", when: "less than", value: 100 },
{ field: "customerType", when: "equal", value: "regular" }
],
hiddenMode: "all" // Hide if BOTH conditions are true
}
}
];
Multiple conditions with OR logic
const fields = [
{
name: "age",
type: "number",
title: "Age"
},
{
name: "parentalConsent",
type: "boolean",
title: "Parental Consent Required",
conditions: {
hiddenWhen: [
{ field: "age", when: "greater than", value: 18 },
{ field: "age", when: "less than", value: 13 }
],
hiddenMode: "any" // Hide if EITHER condition is true
}
}
];
Range-based hiding
const fields = [
{
name: "score",
type: "number",
title: "Test Score (0-100)"
},
{
name: "retakeOption",
type: "boolean",
title: "Retake Test",
conditions: {
hiddenWhen: [
{ field: "score", when: "between", value: [70, 100] }
]
}
}
];
Pattern-based hiding
const fields = [
{
name: "email",
type: "email",
title: "Email Address"
},
{
name: "companyEmail",
type: "email",
title: "Company Email",
conditions: {
hiddenWhen: [
{ field: "email", when: "matches", value: ".*@company\\.com$" }
]
}
}
];
Method 2: Rule Effects
Rule effects provide a more powerful way to hide fields using the rules system.
Basic Syntax
const rules = [
{
name: "hideFieldRule",
effects: [
{
targetField: "fieldToHide",
prop: "hidden",
value: true
}
]
}
];
const fields = [
{
name: "triggerField",
type: "string",
triggers: [
{
rule: "hideFieldRule",
when: "equal",
value: "hide"
}
]
},
{
name: "fieldToHide",
type: "string",
title: "Field to Hide"
}
];
Rule-Based Examples
Hide field based on complex conditions
const rules = [
{
name: "hideDiscountField",
effects: [
{
targetField: "discount",
prop: "hidden",
value: true
}
]
}
];
const fields = [
{
name: "orderTotal",
type: "number",
title: "Order Total",
triggers: [
{
rule: "hideDiscountField",
when: "less than",
value: 50
}
]
},
{
name: "discount",
type: "number",
title: "Discount Amount"
}
];
Toggle field visibility
const rules = [
{
name: "toggleFieldVisibility",
effects: [
{
targetField: "optionalField",
prop: "hidden",
value: true
}
]
},
{
name: "showField",
effects: [
{
targetField: "optionalField",
prop: "hidden",
value: false
}
]
}
];
const fields = [
{
name: "showOptional",
type: "boolean",
title: "Show Optional Field",
triggers: [
{
rule: "showField",
when: "equal",
value: true
},
{
rule: "toggleFieldVisibility",
when: "equal",
value: false
}
]
},
{
name: "optionalField",
type: "string",
title: "Optional Field"
}
];
Complete Examples
Contact Form with Dynamic Fields
const fields = [
{
name: "contactMethod",
type: "select",
title: "Preferred Contact Method",
options: [
{ value: "email", label: "Email" },
{ value: "phone", label: "Phone" },
{ value: "either", label: "Either" }
]
},
{
name: "email",
type: "email",
title: "Email Address",
conditions: {
hiddenWhen: [
{ field: "contactMethod", when: "equal", value: "phone" }
]
}
},
{
name: "phone",
type: "tel",
title: "Phone Number",
conditions: {
hiddenWhen: [
{ field: "contactMethod", when: "equal", value: "email" }
]
}
},
{
name: "preferredTime",
type: "select",
title: "Preferred Contact Time",
options: [
{ value: "morning", label: "Morning" },
{ value: "afternoon", label: "Afternoon" },
{ value: "evening", label: "Evening" }
],
conditions: {
hiddenWhen: [
{ field: "contactMethod", when: "equal", value: "email" }
]
}
}
];
User Registration with Age-Based Fields
const fields = [
{
name: "age",
type: "number",
title: "Age",
required: true
},
{
name: "parentalConsent",
type: "boolean",
title: "Parental Consent Required",
conditions: {
hiddenWhen: [
{ field: "age", when: "greater than", value: 18 }
]
}
},
{
name: "guardianName",
type: "string",
title: "Guardian Name",
conditions: {
hiddenWhen: [
{ field: "age", when: "greater than", value: 18 }
]
}
},
{
name: "guardianPhone",
type: "tel",
title: "Guardian Phone",
conditions: {
hiddenWhen: [
{ field: "age", when: "greater than", value: 18 }
]
}
},
{
name: "seniorDiscount",
type: "boolean",
title: "Senior Discount (65+)",
conditions: {
hiddenWhen: [
{ field: "age", when: "less than", value: 65 }
]
}
}
];
Order Form with Conditional Fields
const rules = [
{
name: "hideShippingFields",
effects: [
{
targetField: "shippingAddress",
prop: "hidden",
value: true
},
{
targetField: "shippingMethod",
prop: "hidden",
value: true
}
]
}
];
const fields = [
{
name: "orderType",
type: "select",
title: "Order Type",
options: [
{ value: "pickup", label: "Pickup" },
{ value: "delivery", label: "Delivery" }
]
},
{
name: "shippingAddress",
type: "subForm",
title: "Shipping Address",
fields: [
{ name: "street", type: "string", title: "Street", width: 100 },
{ name: "city", type: "string", title: "City", width: 50 },
{ name: "state", type: "string", title: "State", width: 25 },
{ name: "zip", type: "string", title: "ZIP", width: 25 }
],
triggers: [
{
rule: "hideShippingFields",
when: "equal",
value: "pickup"
}
]
},
{
name: "shippingMethod",
type: "select",
title: "Shipping Method",
options: [
{ value: "standard", label: "Standard (5-7 days)" },
{ value: "express", label: "Express (2-3 days)" },
{ value: "overnight", label: "Overnight" }
],
triggers: [
{
rule: "hideShippingFields",
when: "equal",
value: "pickup"
}
]
}
];
Advanced Patterns
Cascading Field Visibility
const fields = [
{
name: "hasAddress",
type: "boolean",
title: "Do you have a mailing address?"
},
{
name: "street",
type: "string",
title: "Street Address",
conditions: {
hiddenWhen: [
{ field: "hasAddress", when: "equal", value: false }
]
}
},
{
name: "city",
type: "string",
title: "City",
conditions: {
hiddenWhen: [
{ field: "hasAddress", when: "equal", value: false },
{ field: "street", when: "empty" }
],
hiddenMode: "any"
}
},
{
name: "zip",
type: "string",
title: "ZIP Code",
conditions: {
hiddenWhen: [
{ field: "hasAddress", when: "equal", value: false },
{ field: "street", when: "empty" },
{ field: "city", when: "empty" }
],
hiddenMode: "any"
}
}
];
Multi-Step Form with Progress
const fields = [
{
name: "step",
type: "number",
title: "Current Step",
default: 1,
readOnly: true
},
{
name: "personalInfo",
type: "subForm",
title: "Personal Information",
fields: [
{ name: "firstName", type: "string", title: "First Name", width: 50 },
{ name: "lastName", type: "string", title: "Last Name", width: 50 },
{ name: "email", type: "email", title: "Email", width: 100 }
],
conditions: {
hiddenWhen: [
{ field: "step", when: "not equal", value: 1 }
]
}
},
{
name: "contactInfo",
type: "subForm",
title: "Contact Information",
fields: [
{ name: "phone", type: "tel", title: "Phone", width: 50 },
{ name: "address", type: "text", title: "Address", width: 100 }
],
conditions: {
hiddenWhen: [
{ field: "step", when: "not equal", value: 2 }
]
}
},
{
name: "preferences",
type: "subForm",
title: "Preferences",
fields: [
{ name: "newsletter", type: "boolean", title: "Newsletter", width: 100 },
{ name: "notifications", type: "boolean", title: "Notifications", width: 100 }
],
conditions: {
hiddenWhen: [
{ field: "step", when: "not equal", value: 3 }
]
}
}
];
Best Practices
1. Use Clear Condition Logic
// ✅ Good: Clear and readable
{ field: "age", when: "greater than", value: 18 }
// ❌ Avoid: Unclear conditions
{ field: "age", when: "gt", value: 18 }
2. Group Related Fields
// ✅ Good: Group related fields
const fields = [
{
name: "contactInfo",
type: "subForm",
title: "Contact Information",
fields: [
{ name: "email", type: "email", title: "Email" },
{ name: "phone", type: "tel", title: "Phone" }
]
}
];
3. Use Appropriate Logic Modes
// ✅ Good: Use "all" when both conditions must be true
{
hiddenWhen: [
{ field: "age", when: "less than", value: 18 },
{ field: "parentalConsent", when: "equal", value: false }
],
hiddenMode: "all"
}
// ✅ Good: Use "any" when either condition can be true
{
hiddenWhen: [
{ field: "orderTotal", when: "less than", value: 50 },
{ field: "customerType", when: "equal", value: "regular" }
],
hiddenMode: "any"
}
4. Test Edge Cases
// ✅ Good: Handle edge cases
{
name: "age",
type: "number",
conditions: {
hiddenWhen: [
{ field: "age", when: "less than", value: 0 },
{ field: "age", when: "greater than", value: 120 }
],
hiddenMode: "any"
}
}
Troubleshooting
Common Issues
- Fields not hiding: Check field names match exactly
- Logic not behaving as expected: Verify
hiddenModesetting - Performance issues: Avoid too many complex conditions
Debug Tips
// Add console logging to debug hiding logic
const handleChange = createFormHandler({
fields,
setState: (newData) => {
console.log("Form data:", newData);
setFormData(newData);
},
rules
});
Dynamic field hiding is essential for creating intuitive, user-friendly forms. Use it to reduce cognitive load and guide users through complex form flows.