Repeats and conditional content
Two blocks make a template respond to the data it is rendering: Repeat for each loops over a record’s children, and Show if hides or shows content based on the record’s values. This page covers both.
Repeat for each
Section titled “Repeat for each”A Repeat for each block loops over a child relationship of the base object. The block’s children render once per row: one row per Opportunity Line Item, one row per Contact, and so on.
- Source relationship: pick from the dropdown of available child relationships. The list only shows relationships you have access to. You can also insert a related list straight from the Merge fields panel, which wraps the selection in a Repeat for you.
- Filter (optional): narrow the rows that render, for example
Opportunities.StageName != 'Closed Lost'. - Render mode: a repeat can render as stacked blocks or as table rows, one row per child record, which is the layout invoices, statements and order summaries reach for.
- Inside a Repeat block, the Merge fields panel flips to show the child object’s fields. Insert chips like
{{Opportunities.Amount}}; they resolve per row at runtime. - Five-hop parent lookups also work inside Repeat blocks, for example
Opportunities.Account.Owner.Profile.Name. - Row order: child rows print oldest first, and the preview and the generated document agree on that order. If you need a different order, sort within the record’s own data using a formula field, or narrow the set with the repeat’s filter.
- Nested repeats are supported to arbitrary depth, for example an Account that repeats over its Opportunities, each of which repeats over its line items. Sections, callouts and conditional blocks can sit inside a repeat.
Show if
Section titled “Show if”A Show if block conditionally renders its children based on parent-record data. Expressions are parsed at save time, so any syntax errors surface in the right rail as plain-English messages while you author.
| Construct | Example |
|---|---|
| Comparison | Account.AnnualRevenue > 1000000 |
| Equality | Account.Industry = 'Technology' |
| Inequality | Account.Industry != 'Healthcare' |
| Contains | Account.Name contains 'Acme' |
| Logical AND | Account.IsActive = true AND Account.AnnualRevenue > 1000000 |
| Logical OR | Account.Industry = 'Technology' OR Account.Industry = 'Software' |
| Negation | NOT Account.Industry = 'Healthcare' |
| Grouping | (Account.Industry = 'A' OR Account.Industry = 'B') AND Account.Amount > 1000000 |
| Null check | Account.Description = null |
Operators are =, !=, >, >=, <, <= and contains (case-insensitive substring). Literals are single-quoted strings, decimals including negative ones, true, false and null.
A Show if block carries an optional else branch, so a single block renders one set of children when its condition is met and a different set when it is not, instead of two separate blocks kept in sync with inverted expressions.
Note: the same expression grammar decides whether an item is included in a bundle. See Multi-template bundles.