react-formbridge
Browse documentation
Validationv1.0.2

Conditional logic

Conditional logic lives on the builders themselves, not in ad-hoc component branches.

  • Business rules stay attached to the field contract, next to its label, validation and default value
  • The evaluated state is re-computed on every form change and exposed through the visibility map, so the UI can still react outside the field renderer when needed
  • All helpers compose: multiple visibleWhen* / requiredWhen* / disabledWhen calls on the same builder combine with AND logic
  • The *Any(pairs) variants give you OR logic over a short list of field/value pairs; reach for a predicate when the rule spans more than a couple of fields
  • When a field becomes hidden, its value follows the on-hide policy (default: reset to the builder default)
Conditional.tsxtsx
1const schema = {
2 accountType: field.radio('Account type')
3 .options(['personal', 'business'])
4 .required(),
5 companyName: field.text('Company name')
6 .visibleAndRequiredWhen('accountType', 'business')
7 .clearOnHide(),
8 vatNumber: field.text('VAT number')
9 .visibleWhen('accountType', 'business')
10 .disabledWhen((values) => !values.companyName)
11 .clearOnHide(),
12 referral: field.text('Referral code')
13 .visibleWhenAny([
14 ['source', 'friend'],
15 ['source', 'partner'],
16 ])
17 .keepOnHide(),
18}

Visibility

Visibility helpers live on every builder. Multiple calls compose with AND logic - every rule must pass for the field to stay visible. When a field is hidden its value follows the on-hide policy (default: reset to the field default).

MethodTypeDescription
visibleWhen(field, value?)(field: string, value?: unknown)Visible when the named field strictly equals value. Defaults value to true, so visibleWhen('acceptTerms') is the idiomatic toggle for a boolean gate.
visibleWhen(predicate)((values, ctx) => boolean)Cross-field predicate with access to the full form values snapshot. Use when the rule depends on more than one field.
visibleWhenNot(field, value)(field: string, value: unknown)Visible when the named field is not strictly equal to value. Useful for "hide only on the default option" patterns.
visibleWhenTruthy(field)(field: string)Visible when the named field is truthy. Matches anything that is not false, 0, '', null or undefined.
visibleWhenFalsy(field)(field: string)Mirror of visibleWhenTruthy - visible when the named field is falsy. Handy for "still empty" hints or reminder blocks.
visibleWhenAny(pairs)(pairs: Array<[field: string, value: unknown]>)Visible when at least one [field, value] pair matches (OR logic). Combine with plain visibleWhen(...) calls to express "any of A/B/C AND also X".
visibleAndRequiredWhen(fieldOrPredicate, value?)(field: string, value?: unknown) or ((values, ctx) => boolean)Shorthand that pushes the same rule into both the visibility and required stacks in one call - keeps the two stacks in sync automatically.
InlineExample-2.tsts
1field.text('Company name')
2 .visibleAndRequiredWhen('accountType', 'business')
3 .clearOnHide()

Required

Dynamic required state works like visibility - the rule is evaluated on every form change. A hidden field never raises a required error even if requiredWhen would otherwise match.

MethodTypeDescription
requiredWhen(field, value?)(field: string, value?: unknown)Required when the named field strictly equals value (default true). Multiple calls compose with AND logic.
requiredWhen(predicate)((values, ctx) => boolean)Cross-field predicate - use when the decision needs multiple fields.
requiredWhenAny(pairs)(pairs: Array<[field: string, value: unknown]>)Required when any [field, value] pair matches (OR logic).
InlineExample-2.tsts
1field.text('Referral code')
2 .requiredWhenAny([
3 ['source', 'friend'],
4 ['source', 'partner'],
5 ])

Disabled

Disabled rules toggle the field interactivity without removing it from the layout. The field still submits its current value, it just cannot be edited by the user.

MethodTypeDescription
disabledWhen(field, value?)(field: string, value?: unknown)Disabled when the named field strictly equals value (default true). Multiple calls compose with AND logic.
disabledWhen(predicate)((values, ctx) => boolean)Cross-field predicate form. There is intentionally no disabledWhenAny - compose a predicate if you need OR logic.
InlineExample-2.tsts
1field.text('Invoice email')
2 .disabledWhen((values) => values.billingSameAsContact === true)

Hidden value behavior

On-hide behavior controls what happens to a field value when the field becomes invisible. It only runs on the hide transition - re-showing the field never mutates the value.

MethodTypeDescription
resetOnHide()() => thisReset the field to its builder default when it becomes hidden. This is the default if you never call any of these helpers.
clearOnHide()() => thisClear the field on hide (empty string, null, or the empty form of the field type). Use it when a stale value would be confusing if the user toggles the gate back open.
keepOnHide()() => thisKeep the value as-is while hidden. Pairs well with persistence so the user never loses input when flipping a branching field back and forth.
InlineExample-2.tsts
1// Default - reset
2field.text('Company name').visibleWhen('accountType', 'business')
3// Clear the input when the branch is not selected
4field.text('VAT').visibleWhen('accountType', 'business').clearOnHide()
5// Keep the value across visibility toggles
6field.text('Notes').visibleWhen('showNotes').keepOnHide()