
# Form Conditional Logic

Conditional logic makes a form respond to what the submitter enters: fields appear, become required, or grey out depending on the values of other fields. Three rule properties drive this — `visibleWhen`, `requiredWhen`, and `disabledWhen` — and all three share the same condition shape, so once you learn one you know all three.

```yaml
fields:
  - {
      kind: standalone,
      name: has_company,
      inputType: checkbox,
      label: I'm signing up on behalf of a company,
    }
  - kind: standalone
    name: company_name
    inputType: short-text
    label: Company name
    visibleWhen: { field: has_company, operator: eq, value: true }
    requiredWhen: { field: has_company, operator: eq, value: true }
```

## Rule Properties

| Property       | Effect when the condition is **true**                                         |
| -------------- | ----------------------------------------------------------------------------- |
| `visibleWhen`  | The field (or section) is shown. When false, it is hidden and not submitted.  |
| `requiredWhen` | The field becomes required. When false, it is optional.                       |
| `disabledWhen` | The field is disabled (greyed out, not editable). When false, it is editable. |

Each rule lives on a field's common base, so it can be applied to any input-bearing field kind. `section` fields support `visibleWhen` to show or hide an entire labeled group.

## Simple Conditions

A simple condition compares one field's current value against a target using an operator.

| Property   | Description                                                                                                             |
| ---------- | ----------------------------------------------------------------------------------------------------------------------- |
| `field`    | Name of the field whose value is evaluated.                                                                             |
| `operator` | Comparison operator (see table below).                                                                                  |
| `value`    | Value to compare against. A scalar for comparison operators; an array for membership; omitted for `empty` / `notEmpty`. |

### Condition Operators

| Operator   | Meaning                               |
| ---------- | ------------------------------------- |
| `eq`       | Equals the value.                     |
| `neq`      | Does not equal the value.             |
| `contains` | String/array contains the value.      |
| `empty`    | Field has no value (ignores `value`). |
| `notEmpty` | Field has a value (ignores `value`).  |
| `gt`       | Greater than the value.               |
| `gte`      | Greater than or equal to the value.   |
| `lt`       | Less than the value.                  |
| `lte`      | Less than or equal to the value.      |
| `in`       | Value is one of the array members.    |
| `notIn`    | Value is none of the array members.   |

```yaml
fields:
  - kind: standalone
    name: contact_method
    inputType: select
    label: Preferred contact method
    options:
      - { value: email, label: Email }
      - { value: phone, label: Phone }
  - kind: standalone
    name: phone
    inputType: phone
    label: Phone number
    visibleWhen: { field: contact_method, operator: eq, value: phone }
    requiredWhen: { field: contact_method, operator: eq, value: phone }
```

## Compound Conditions (AND / OR)

Conditions compose with `and` / `or` and may nest arbitrarily. An `and` block is true when **every** child is true; an `or` block is true when **any** child is true.

```yaml
fields:
  - kind: standalone
    name: expedite_reason
    inputType: long-text
    label: Why does this need to be expedited?
    visibleWhen:
      and:
        - { field: priority, operator: in, value: [high, urgent] }
        - or:
            - { field: budget, operator: gte, value: 10000 }
            - { field: vip_customer, operator: eq, value: true }
```

:::callout
**`disabledWhen` keeps a field present.** A disabled field still renders and still submits its current value — it just cannot be edited. Use `visibleWhen` when a field should disappear and stop submitting entirely; use `disabledWhen` when the value should remain but be locked.
:::

## Step Branching

In multi-step layouts, conditions also drive flow control. A step's `goToWhen` rules let a true condition jump to a different step instead of the linear next one, and a step-level `visibleWhen` skips the entire step. See [Multi-Step Forms](/en/docs/form-multi-step) for the full branching model.

```yaml
steps:
  - id: account-type
    title: Account type
    fields: [plan]
    goToWhen:
      - when: { field: plan, operator: eq, value: enterprise }
        goTo: sales-contact
  - id: billing
    title: Billing
    fields: [card_number, billing_email]
  - id: sales-contact
    title: Talk to sales
    fields: [company, seats]
```

## Conditions Through `formRef`

When a top-level form is embedded in a page via the form control's `formRef`, all of its conditional logic comes along — `visibleWhen`, `requiredWhen`, `disabledWhen`, and step branching behave identically whether the form is rendered at `/forms/{name}` or inline on a host page. Define the conditions once on the form; every embed inherits them. See [Form Controls](/en/docs/form-controls).

## Related Pages

- [Form Fields](/en/docs/form-fields) — where `visibleWhen` / `requiredWhen` / `disabledWhen` live.
- [Multi-Step Forms](/en/docs/form-multi-step) — step-level visibility and `goToWhen` branching.
- [Forms Overview](/en/docs/forms-overview) — form metadata and submit targets.
- [Form Controls](/en/docs/form-controls) — embedding a conditional form in a page.
