Skip to main content

Conditional visibility (visibleWhen)

Any field can carry a condition. It is drawn only when that condition is true:

{ type: "text", content: "Corporate discount", visibleWhen: 'customer.type == "company"' }
{ type: "table", name: "overdue", visibleWhen: "NOT paid" }
{ type: "kpi", visibleWhen: "total > 1000 AND NOT cancelled" }

The condition is an expression without braces — it is not a template, so write total > 1000, not {total > 1000}. Everything the {...} engine understands works here: paths, comparisons, AND/OR/NOT, functions (COUNT(items) > 0), arithmetic. Truthiness follows the format's rule: empty, "0" and "false" are false, anything else is true — so a bare path works too (visibleWhen: "paid").

In <Designer> there is a "Show only when" input next to X/Y/width/height, and a syntax error appears live underneath it.

It works on every field type, tables and repeated sections included, and on the repeating bands (header/footer/margin). A band's condition may use pageNumber/pageCount, because those are resolved per page — so "only on the last page" is:

{ type: "text", content: "Please check the totals", visibleWhen: "pageNumber == pageCount" }

What hiding does to the layout​

Hiding an item gives back its height, and nothing else:

visible "meio" hidden
20mm ┌───────────┐ topo 20mm ┌───────────┐ topo
└───────────┘ (10mm tall) └───────────┘
40mm ┌───────────┐ meio
└───────────┘ (10mm tall)
60mm ┌───────────┐ abaixo 50mm ┌───────────┐ abaixo <- moved up 10mm
└───────────┘ └───────────┘

What follows moves up by exactly the hidden height; the spacing authored on both sides still applies. A hidden table gives back all of its pages the same way.

One exception, and it is the useful one: hiding a field that shares a row with visible neighbours leaves the hole. Fields at the same authored Y are one row — the neighbours need their place, so the row keeps its height. Hide them all and the whole row goes.

An invalid condition means visible​

A condition that does not parse counts as visible, never hidden. A typo must not make a field vanish from a report in silence — the editor flags the field (alert icon in the field list, message under the input) and the field keeps showing until someone fixes it.

That is the same trade-off the {...} tokens make: generation is tolerant, the editor is strict. A malformed expression renders empty rather than failing generatePdf — one blank field is better than no document — and the error surfaces before generating, where it can still be fixed.

To check it yourself (a backend refusing a bad template, or your own editor UI):

import { expressionError, templateExpressionErrors, expressionErrors } from "json-pdf-designer";
// also available from "json-pdf-designer/server", except expressionErrors' UI helpers

expressionError("total > 1000"); // null — valid
expressionError("total >"); // "Expressão incompleta (posição 8 em …)"
templateExpressionErrors("a={x} b={y)"); // [{ token: "{y)", message: … }]
expressionErrors(schema, binding); // every expression a field carries