The form builder designs the forms shown when a transition runs. It is how each step of a process asks for exactly the information that step needs, without adding fields to the shipment record that most shipments will never use.
Structure
A form has a title, a schema name identifying what it collects against, and a layout of 1 to 4 columns containing sections.
Each section has:
| Setting | Purpose |
|---|---|
| Name | Its heading. |
| Columns | How many columns inside the section (1–4). |
| Span | How much of the parent width it occupies (1–4). |
| Schema name | Which entity the section's fields belong to. |
| Entity relationship | How that entity is linked — see below. |
A section can therefore collect data about something other than the shipment itself. The entity relationship describes the link: which field on the main record points at it, whether it is a single related record or an array of them, and which key joins them.
That is how one transition form can capture container detail, or several packages, in the same submission as the shipment fields.
Field types
| Type | Use for |
|---|---|
text | Free text |
number | Numeric input |
date | Dates |
textarea | Long text |
select | A fixed list |
checkbox | A yes/no box |
toggle | A yes/no switch |
table | Repeating rows |
document | File upload |
autoCompleteSelector | Type-ahead against a list |
fetcher-combobox-with-config | Type-ahead against live data from another module |
dynamicComboBox | A list whose options depend on other answers |
calculated | A value derived by formula from other fields |
custom | A purpose-built component |
Each field carries a label, placeholder, span (1–4), and an include flag that lets you keep a field defined but off the form.
Calculated fields
A calculated field evaluates a formula over other fields — numbers, operators and parentheses. Use it for anything that should never be typed twice: a total, a chargeable weight, a difference between two dates.
Anything derivable should be calculated rather than entered. Every hand-keyed derived value is a future discrepancy.
Validation
| Rule | Applies to |
|---|---|
| Required | Any field |
| Min / Max | Numbers |
| Min length / Max length | Text |
| Pattern | Text matching a specific format |
| Disable future | Dates that cannot be in the future |
Disable future is worth using on actual-event dates. An actual departure recorded next week is a typo every time, and it is far cheaper to block it than to find it later in a report.
Conditional visibility
A field can be shown or hidden depending on another field's value, using a condition of the form field · operator · value, with operators:
eq · neq · gt · lt · gte · lte · contains · notContains · exists
This is how one form serves several cases: show the reefer fields only when the container type is refrigerated, show hazardous class and UN number only when hazardous is ticked, show air fields only for air shipments.
Conditional visibility is better than a longer form or a second form. Operators fill in what is in front of them, and a form that only shows relevant fields gets filled in correctly.
Design guidance
- Ask only for what is knowable at that step. Fields the operator cannot yet answer get filled with placeholders, and placeholders are worse than blanks because nothing downstream can tell them apart.
- Mark required only what genuinely blocks progress. Over-use of required trains people to enter rubbish to get past the form.
- Group by how the work happens, not by how the data is stored. The section order should match the order the operator finds things out.
- Test the form by running the transition on a real record before releasing it. Conditional visibility and calculated fields are easy to get subtly wrong and obvious once seen.
Where forms are attached
Forms are attached to transitions, not to shipments. See Running a transition. Changing a form changes what every future run of that transition asks for; records already captured keep what they captured.
Last updated 9 September 2026