Skip to main content
Menu
On this page

Calculated

Show a derived number computed from other answers, recomputed server-side on submit.

Rendered by the SDK
@usefillo/react
$78.00
Interactive local preview. Nothing is submitted.

The calculated field derives a number from other answers — order totals, scores, quantities — and stores it like any other answer. It renders as a read-only value, never an input: respondents watch it update live as they answer, and the server recomputes it from the validated answers on submit, so a tampered client value is ignored by construction.

Options

OptionTypeDefaultBehavior
calcCalcExprrequiredThe typed expression tree to evaluate
decimalsnumbernoneRounds the stored value (0–6, half-away-from-zero)
prefixstringnoneDisplay-only text before the value, e.g. $
suffixstringnoneDisplay-only text after the value, e.g. kg

A calculation may read number, rating, linear_scale, and other calculated fields. Evaluation is identical live and on submit because both run over the answers as they will be stored: strings are trimmed, an unchecked checkbox or otherwise empty answer reads as unanswered, and a source that is logic-hidden or on a jump-skipped page reads as unanswered — even if a value was typed there before the flow changed. Any unanswered operand (or a division by zero) makes the whole result unanswered — the key is simply absent from the response, piping renders empty, and the grid shows an empty cell. Calculated fields are never required and are never prefilled from the URL.

The expression tree

calc is a typed AST, not a formula string:

ts
type CalcExpr =
  | { op: "value"; fieldId: string }
  | { op: "const"; value: number }
  | { op: "add" | "mul" | "min" | "max"; args: CalcExpr[] }
  | { op: "sub" | "div"; left: CalcExpr; right: CalcExpr }
  | { op: "round"; arg: CalcExpr; decimals?: number }
  | { op: "if"; when: Condition[]; then: CalcExpr; else: CalcExpr };

if.when uses the same condition model as visibility rules and page jumps, so one condition language covers all three. Schema validation rejects a reference to a missing or non-numeric field and any reference cycle outright — a calculated field never silently degrades.

Add a calculated field

In the dashboard, select Add block, choose Calculated value, then pick an operation (sum, difference, product, quotient, minimum, or maximum), the numeric fields it reads — from any page — and an optional constant term. Decimals, prefix, and suffix sit alongside. The editor compiles that to a one-level expression; fields that would create a reference cycle aren't offered.

Deeper expressions — nesting, round, if — are written in code. When a form defines one, the builder shows a read-only "Edited in code" notice instead of an editor that would flatten it.

In code:

ts
const orderTotal = {
  id: "order_total",
  kind: "calculated",
  label: "Order total",
  calc: {
    op: "mul",
    args: [
      { op: "value", fieldId: "quantity" },
      { op: "const", value: 19.5 },
    ],
  },
  decimals: 2,
  prefix: "$",
} as const;

The computed value participates everywhere an answer does: pipe it with {{order_total}}, branch visibility or page jumps on it, and read it from the responses grid, CSV exports, and webhook payloads. Piping inserts the plain number; the display row, grid, and exports apply decimals, prefix, and suffix through the shared formatter.

SDK compatibility

A form containing a calculated field serves a raised minimum SDK version (0.11.0) from the public form endpoint. Older embeds would render the form without the calculated row and mis-run any logic that reads it, so they fail fast with an update message instead.

  • Conditional logic: Branch visibility and page flow on answers, including calculated ones.
  • Answer piping: Render the computed value inside labels and text blocks.

Updated

Was this page helpful?