Skip to content

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 ​

dart
// 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 ​

dart
// Hide confirmation field until email is entered
.text('email_confirm', title: 'Confirm Email')
  .hideWhen(When.fieldEmpty('email'))
  .required()

Boolean Toggle ​

dart
// 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.

dart
// 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:

dart
.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) ​

dart
// 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) ​

dart
// 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:

dart
// 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:

dart
// 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:

dart
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:

dart
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 ​

dart
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 ​