Skip to main content
A form rule makes part of a form react to what has been answered so far: a row that appears only for one kind of request, a field that becomes required once a box is ticked, a total that fills itself in.

QuivaWorks has two rule engines. This is the other one

Nothing carries across between them. An operator, a syntax or a pattern from the flow Rules documentation will not work on a form, and the reverse is equally true. If you have used the flow Rules step, treat this page as an unrelated language. The operators that work here are listed below and nowhere else.
They share a word and nothing else.

What a rule is

A rule is attached to one thing on the form — a placed field, a row, or a presentational element — and has three parts:

A property

What the rule drives. Visible, Required, Disabled, Read-only or Value on a field; Visible on a row.

A condition

A JsonLogic expression evaluated against the answers so far.

A description

Plain English, for whoever opens the form next. Optional, and worth writing every time.
Rules live on the placed element, not on the Record Set — so two forms over the same fields can have completely different logic.
One rule per property per element. The editor never creates a second, and a hand-written second rule for the same property causes the form to disagree with itself: the field renders according to the last rule but is treated as hidden if any of them says hidden. Combine conditions into one rule with and / or instead.

Writing a condition

A condition is a JSON object with one key — the operator — whose value is the list of things it operates on. {"var": "field_name"} reads an answer.
Read as: the answer to request_type is equipment. var reads any field on the form, not just nearby ones. Nested fields use a dot — {"var": "contact.country"} — exactly as they are written when placing a field. You rarely type this by hand. The Rules tab’s Generate box turns a plain-language sentence into the expression for you; see The rule assistant. The Raw tab is there when you want to write or adjust the JSON directly.

The operators that work

This is the complete set. Anything not on this list does not exist, and a rule using it is ignored when the form runs.
+ - * / % min maxMostly used with the Value property, to fill a field in from other answers.
Inside these, {"var": "…"} refers to the item, not the record: {"var": "qty"} is that item’s quantity.
The plausible names that are not there. Every one of these was tried against the engine that ships in the product, and every one is absent:includes · startsWith · endsWith · contains · count · size · sum · avg · toLowerCase · toUpperCase · trim · split · join · match · regex · now · date · dateDiff · abs · round · floor · ceil · number · string · typeof · isEmpty · notEmpty · between · logFor contains text use in with the text first. For is blank use !!. For between use the three-operand range form of <=. For matches a pattern, put a pattern on the field’s schema instead — validation can enforce it, a rule cannot test it. There is no string-case, rounding or date arithmetic available to a form rule at all; compute those in a flow and write the answer back.
Use var, not val. Both evaluate correctly, but only var is understood by the Form logic overview, so a rule written with val appears to depend on nothing and the “this rule reads a field that is not on the form” warning stops working for it.

How values behave when nothing has been answered

The most common surprise is a rule that reacts to a field nobody has filled in yet. These are the behaviours worth knowing, all of them observed rather than assumed.
That fifth row is a real trap. Show this when the headcount is under ten shows the field to everybody who has not answered the headcount yet, because an unanswered number counts as lower than everything. Guard the comparison:
For this field, or a stand-in when it is blank, if is the reliable form — the var fallback and ?? both let an empty answer through:
A multi-valued control on a text field stores its answers as one comma-separated string, so {"in": ["…", {"var": "accessories"}]} is a substring test, not a membership test — "top" matches "laptop,desktop". Where this matters, type the field as a list so in tests real membership.

When a rule cannot be evaluated

A condition the engine cannot run — an operator that does not exist, a malformed expression — has no opinion, and the rule is skipped entirely:
equals is not an operator, so that rule does nothing at all — the field it guards behaves as if the rule were not there. That is deliberate: a question showing when it should not is a nuisance, a question that has silently vanished is a lost answer. The rule card says so while you are writing it. A rule naming an operator the engine does not have carries a red note above the description, listing the offending names:
This rule uses an operator the form engine does not support: equals. It will be ignored when the form runs.
Two habits still worth keeping:
1

Check the summary line on the rule card

Every rule shows a one-line plain-English summary in its header — Show this element when request_type is “equipment”. If yours instead reads like a function call — contains(notes, "urgent") — the summary could not be produced. Arithmetic and list operators read that way legitimately, so it is a prompt to look, not a verdict.
2

Preview the form both ways

Switch to Preview and answer the driving question each way. A field that appears in both states has a condition that is not doing its job — either broken, or always true.
An unfinished rule is harmless. A rule created but never given a condition has no opinion — it neither shows nor hides anything, and the property keeps whatever it would have had. It shows in the Rules tab as Not configured yet. Tidy them up anyway: an empty rule reads to the next person as if the case has been handled.To force a state permanently, use a hard always or never rather than an empty condition.

What conditional visibility does and does not clear

When a form is submitted, anything hidden at that moment is stripped out before validation and before saving. That is the point of conditional forms: an answer given under one branch and then hidden when the branch changed does not survive onto the record, and does not block submission by being required. The clearing follows every container that removes a field from view — a row, a Card, a Collapsable card, a Repeater, and the field’s own rule. A field is cleared when it sits, at any depth, under something hidden. Required-ness follows visibility, on both sides. A hidden field’s answer is pruned and its schema required is skipped, and the form tells the server which refs its rules hid so the save is not rejected either. A question nobody could see never blocks a submission.
This applies to the rules the form evaluates. Writing to a record through the API is unaffected: a required field is still required unless the caller names it in hidden_fields. See Records.

Which answers a rule can see

By default, every rule reads the whole record being filled in, wherever on the form it is attached. A rule on the last row can read the first question. That stays true even when the form is being filled a section or a step at a time: each step is checked against the whole record, and only the messages belonging to that step’s own fields are shown. A rule on step four that depends on an answer from step one therefore evaluates correctly, and a required field further along does not block the step in front of it.

Rules inside a repeater

A repeater is the exception. Its item fields render against one item, so a rule attached to a field inside a repeater reads that item’s answers, not the record’s. Inside a line_items repeater, {"var": "qty"} is this line’s quantity.
A rule inside a repeater cannot reach a field outside it. If a repeater’s fields need to react to a top-level answer, put the rule on the row containing the whole repeater instead — remembering that this hides the repeater without clearing what is in it.
To ask about a repeater’s contents from outside it, use the list operators on the repeater’s own field:

Worked examples

Every example below has been run against the engine that ships in the product.
Property: Visible, on the row.
Property: Required, on the field.
And its negation, for any team except these:
Case-sensitive, and there is no way to make it otherwise — there is no lower-casing operator.
Property: Value.
A computed value is written into the record, so it is validated, saved, and visible to any other rule that reads it.
Property: Value.
Property: Value.
A condition of true or false, written in the Raw tab, is a complete and valid rule. The summary reads always or never (always off). Useful for parking a field as read-only, or for switching a section off without deleting it.

Seeing all the logic at once

Form settings → View form logic opens a read-only overview of every rule on the form, grouped by the element it affects, showing which answers each condition watches and what it drives. It flags a rule that reads a field not placed on this form — the usual reason a rule that looks right never fires.