Dynamic Behavior
This guide covers using the rules system to add dynamic behavior to forms: showing/hiding fields, enabling/disabling fields, setting values, and adding conditional validations.
Show/Hide Fields
The most common rule pattern. Use showWhen to show a field when a condition is met (hidden otherwise), or hideWhen for the inverse.
Basic Visibility
// Show payment fields only for paid enrollment
.select('payment_method', title: 'Payment Method')
.option('credit_card', title: 'Credit Card')
.option('bank_transfer', title: 'Bank Transfer')
.showWhen(When.fieldEquals('enrollment_type', 'paid'))
.required()Hide When Empty
// Hide confirmation field until email is entered
.text('email_confirm', title: 'Confirm Email')
.hideWhen(When.fieldEmpty('email'))
.required()Boolean Toggle
// Show international fields when checkbox is checked
.text('passport_number', title: 'Passport Number')
.showWhen(When.fieldTrue('is_international'))
.required()
.text('visa_type', title: 'Visa Type')
.showWhen(When.fieldTrue('is_international'))Enable/Disable Fields
Use enableWhen and disableWhen to control field interactivity.
// Disable course selection after enrollment is confirmed
.select('course', title: 'Course')
.option('CS101', title: 'Intro to CS')
.option('CS201', title: 'Data Structures')
.disableWhen(When.fieldTrue('is_confirmed'))
// Enable "Other" text field only when "Other" is selected
.text('other_reason', title: 'Please specify')
.enableWhen(When.fieldEquals('reason', 'other'))Section-Level Rules
Sections can have visibility rules that show/hide all child fields together:
.section('Payment Details', (s) => s
.select('payment_method', title: 'Payment Method')
.option('credit_card', title: 'Credit Card')
.option('bank_transfer', title: 'Bank Transfer')
.required()
.text('card_number', title: 'Card Number')
.showWhen(When.fieldEquals('payment_method', 'credit_card'))
.required()
.text('bank_account', title: 'Bank Account')
.showWhen(When.fieldEquals('payment_method', 'bank_transfer'))
.required(),
rules: [When.fieldEquals('enrollment_type', 'paid').show()],
)The entire "Payment Details" section appears only when enrollment type is "paid". Within it, card number and bank account fields toggle based on the payment method.
Compound Conditions
Combine multiple conditions with AND/OR logic:
All Conditions Must Match (AND)
// Show international payment fields only for paid + international
.text('swift_code', title: 'SWIFT Code')
.showWhen(When.allOf([
When.fieldEquals('enrollment_type', 'paid'),
When.fieldTrue('is_international'),
]))Any Condition Must Match (OR)
// Show special instructions for either paid or sponsored students
.text('special_instructions', title: 'Special Instructions')
.showWhen(When.anyOf([
When.fieldEquals('enrollment_type', 'paid'),
When.fieldEquals('enrollment_type', 'sponsored'),
]))Dynamic Validation
Add or remove validations based on form state using ValidationAction:
// Make payment method required only for paid enrollment
TextField(
name: 'payment_method',
title: 'Payment Method',
rules: [
FormFieldRule(
condition: StringCondition(
targetField: 'enrollment_type',
operator: StringOperator.equals,
value: 'paid',
),
action: ValidationAction(
validationType: 'required',
errorMessage: 'Payment method is required for paid enrollment',
addWhenTrue: true,
),
),
],
)When enrollment_type changes to "paid", the required validation is activated. When it changes to something else, the validation is deactivated.
Setting Values
Use SetValueAction to set a field's value when a condition is met:
// When "same as billing" is checked, auto-fill shipping address
TextField(
name: 'shipping_address',
title: 'Shipping Address',
rules: [
FormFieldRule(
condition: BooleanCondition(
targetField: 'same_as_billing',
operator: BooleanOperator.isTrue,
),
action: SetValueAction(value: ''),
),
],
)Focus Management
Move focus to a specific field when a condition changes:
TextField(
name: 'payment_method',
title: 'Payment Method',
rules: [
FormFieldRule(
condition: StringCondition(
targetField: 'enrollment_type',
operator: StringOperator.equals,
value: 'paid',
),
action: FocusAction(
targetFieldName: 'payment_method',
focusWhenTrue: true,
),
),
],
)Compound Actions
Apply multiple actions simultaneously:
FormFieldRule(
condition: StringCondition(
targetField: 'enrollment_type',
operator: StringOperator.equals,
value: 'paid',
),
action: CompoundAction(actions: [
VisibilityAction(showWhenTrue: true),
ValidationAction(
validationType: 'required',
errorMessage: 'Required for paid enrollment',
addWhenTrue: true,
),
]),
)Runtime vs. Visual Editor Defaults
The runtime model supports VisibilityAction, EnabledAction, FocusAction, SetValueAction, CompoundAction, and ValidationAction. The default visual editor palette exposes the common field-editing actions: visibility, enabled state, and validation. Apps can register additional action types through FormEditorDescriptor when those actions should be authored visually.
LMS Example: Enrollment with Payment Logic
final form = FormBuilder(title: 'Course Enrollment')
// Student info
.text('name', title: 'Full Name').required()
.text('email', title: 'Email').required().email()
// Course and enrollment type
.select('course', title: 'Course')
.option('flutter', title: 'Flutter Development')
.option('dart', title: 'Dart Fundamentals')
.required()
.select('enrollment_type', title: 'Enrollment Type')
.option('open', title: 'Open (Free)')
.option('paid', title: 'Paid')
.option('sponsored', title: 'Sponsored')
.required()
// International student flag
.boolean('is_international', title: 'International Student')
// Payment section (visible for paid enrollment only)
.section('Payment Information', (s) => s
.select('payment_method', title: 'Payment Method')
.option('credit_card', title: 'Credit Card')
.option('bank_transfer', title: 'Bank Transfer')
.required()
.text('card_number', title: 'Card Number')
.showWhen(When.fieldEquals('payment_method', 'credit_card'))
.required()
.text('swift_code', title: 'SWIFT/BIC Code')
.showWhen(When.allOf([
When.fieldEquals('payment_method', 'bank_transfer'),
When.fieldTrue('is_international'),
]))
.required(),
rules: [When.fieldEquals('enrollment_type', 'paid').show()],
)
// Sponsor section (visible for sponsored enrollment only)
.section('Sponsor Details', (s) => s
.text('sponsor_name', title: 'Sponsor Name').required()
.text('sponsor_email', title: 'Sponsor Email').required().email(),
rules: [When.fieldEquals('enrollment_type', 'sponsored').show()],
)
.build();Next Steps
- Multi-Step Forms -- StepForm wizard patterns
- Rules System -- Complete conditions and actions reference
- Cross-Field Validation -- Cross-field validation patterns