What you need to know
- A rule changes one question, its target, based on answers to questions that come before it.
- There are four actions:
show,hide,requireandskip. - A rule only runs after its source question has been answered. Questions the respondent never saw count as unanswered.
- A question that has a
showrule stays hidden until one of its show rules matches. - Conditions compare option IDs for choice questions, never their labels.
- Logic is available on every plan.
Rule format
Rules live in the definition's rules list:
| Key | Notes |
|---|---|
id |
A UUIDv7, unique within the form. |
sourceId |
The question whose answer the rule waits for. For skip, the jump happens right after this question. |
targetId |
The question the rule acts on. It must come after the source. |
mode |
all: every condition must match. any: one matching condition is enough. |
action |
show, hide, require or skip. |
conditions |
Up to 20 conditions, each {fieldId, operator, value}. fieldId is the source question or one before it. |
Most rules check the source question itself, so sourceId and each condition's fieldId are the same. They differ when a rule waits for one question and then also checks earlier answers, such as "after the budget question, if the budget is over 5000 and the project type is Website".
A form can have up to 300 rules.
What each action does
show: the target appears only when the rule matches.hide: the target is hidden when the rule matches.require: the target becomes required when the rule matches. No rule makes a shown question optional, so for "required only when…" leaverequiredfalse and add arequirerule.skip: after the respondent answers the source question, the form jumps to the target and skips every question in between. It only jumps forward. To end a form early, hide the remaining questions instead.
A require rule cannot target a statement, because statements collect no answer.
How rules run
trulyform goes through the questions in order:
- For each question, it checks the
showandhiderules that target it, in the order they appear inrules. The first one that matches decides whether the question is shown or hidden. - If none match, the question is hidden when at least one
showrule targets it, and shown otherwise. - A shown question is required when its
requiredis true or arequirerule targeting it matches. - After a question is answered, the first matching
skiprule whose source is that question jumps forward.
A rule never matches while its source question has no answer, whatever its conditions, so it cannot react to the source being left blank. Once the source has an answer, a condition on a question that is unanswered, hidden or skipped sees no answer: only is_empty matches it.
A hidden or skipped question is never required, even when its required is true. A follow-up shown by a show rule can therefore be required: true: it is enforced only when it appears.
Rules always run on the current answers. When a respondent goes back and changes an answer, the questions that are shown, hidden and required change with it.
Conditions
| Operator | Meaning |
|---|---|
eq |
Equals the value. Text comparisons ignore letter case and surrounding spaces. |
neq |
Does not equal the value. |
gt |
Greater than the value. Numbers compare as decimals; dates compare chronologically. |
gte |
Greater than or equal to the value. |
lt |
Less than the value. |
lte |
Less than or equal to the value. |
contains |
Text: contains the value. Multiple choice and ranking: the answer includes this option ID. |
not_contains |
The opposite of contains. |
has_value |
The question has an answer. Takes no value. |
is_empty |
The question has no answer, including when it was skipped or hidden. Takes no value. |
any_of |
The answer includes at least one of the listed option IDs. The value is a list. |
Comparison values by question type:
| Kind | Operators | Comparison value |
|---|---|---|
short_text |
eq, neq, has_value, is_empty, contains, not_contains |
A string, such as "yes". |
long_text |
eq, neq, has_value, is_empty, contains, not_contains |
A string, such as "yes". |
email |
eq, neq, has_value, is_empty, contains, not_contains |
A string, such as "yes". |
phone |
eq, neq, has_value, is_empty, contains, not_contains |
A string, such as "yes". |
number |
eq, neq, has_value, is_empty, gt, gte, lt, lte |
A number or decimal string, such as "7" or "2.5". |
date |
eq, neq, has_value, is_empty, gt, gte, lt, lte |
A date as "YYYY-MM-DD". |
single_choice |
eq, neq, has_value, is_empty |
An option ID from this question. |
dropdown |
eq, neq, has_value, is_empty |
An option ID from this question. |
multiple_choice |
contains, not_contains, any_of, has_value, is_empty |
An option ID from this question. any_of takes a list of option IDs. |
consent |
eq, neq, has_value, is_empty |
true or false. |
nps |
eq, neq, has_value, is_empty, gt, gte, lt, lte |
A number or decimal string, such as "7" or "2.5". |
opinion_scale |
eq, neq, has_value, is_empty, gt, gte, lt, lte |
A number or decimal string, such as "7" or "2.5". |
ranking |
contains, not_contains, any_of, has_value, is_empty |
An option ID from this question. any_of takes a list of option IDs. |
matrix |
has_value, is_empty |
Only has_value and is_empty. |
file_upload |
has_value, is_empty |
Only has_value and is_empty. |
statement |
None | Statements cannot be used in conditions. |
website |
eq, neq, has_value, is_empty, contains, not_contains |
A string, such as "yes". |
- Text comparisons ignore letter case and the spaces around the answer. Website answers compare the saved address exactly, such as "https://example.com".
- Choice values are option IDs. For
any_of, the value is a list of option IDs. - NPS and opinion scale questions with a comment box compare the score.
- A ranking answer always contains every option, so
containson a ranking is always true.
Tips
- Ask a follow-up only when it applies:
showthe follow-up when the earlier answer matches. Useskipinstead to jump past several questions at once. - "Other, please specify": add an Other option, then a short text question right after it with a
showrule on that option. - Different text for different people: a form has one ending, so pipe answers into it, or add a statement just before the end and
showit only to some respondents. - Several triggers for one question: use
mode: "any"with several conditions, or add severalshowrules.
Example
The workshop registration asks which ticket the person wants and uses that answer three times:
Workshop registration: rules
[
{
"id": "01990000-0000-7000-8000-000000000121",
"sourceId": "01990000-0000-7000-8000-000000000103",
"targetId": "01990000-0000-7000-8000-000000000105",
"mode": "all",
"action": "hide",
"conditions": [{"fieldId":"01990000-0000-7000-8000-000000000103","operator":"eq","value":"01990000-0000-7000-8000-000000000112"}]
},
{
"id": "01990000-0000-7000-8000-000000000122",
"sourceId": "01990000-0000-7000-8000-000000000103",
"targetId": "01990000-0000-7000-8000-000000000106",
"mode": "all",
"action": "show",
"conditions": [{"fieldId":"01990000-0000-7000-8000-000000000103","operator":"eq","value":"01990000-0000-7000-8000-000000000111"}]
},
{
"id": "01990000-0000-7000-8000-000000000123",
"sourceId": "01990000-0000-7000-8000-000000000103",
"targetId": "01990000-0000-7000-8000-000000000107",
"mode": "all",
"action": "require",
"conditions": [{"fieldId":"01990000-0000-7000-8000-000000000103","operator":"eq","value":"01990000-0000-7000-8000-000000000111"}]
}
]
Select the text to copy it.
- The first rule hides the session date question for online tickets.
- The second shows the dietary needs question only for in-person tickets.
- The third makes the phone number required for in-person tickets.
The job application uses a skip rule: people who have never worked on a remote team jump past the follow-up question about it.