Create Dynamic Tables with Conditional Logic in Dochly
What the table element does
A table in a Dochly template is bound to a Salesforce related list (for example, Opportunity Line Items on an Opportunity, or Contacts on an Account). When a document is generated, Dochly repeats the table's data row once for every record in that related list, filling in the merge fields you've mapped to each column.
The table is flat: every record in the related list becomes a row, and every configured column appears on every row. There is no per-row condition, no per-cell logic, and no way to conditionally hide a column — the table simply reflects whatever is in the related list, laid out in the columns you set up.
Lists every record from the connected related list as a row, using the column layout and merge fields you configured when you built the table. Reordering, adding, or removing columns is done once, in the template editor, for the whole table.
It can't show or hide individual rows based on a field value, hide a column when it's not relevant, switch a cell's content based on other data in the row, display a custom message when the related list is empty, or calculate a conditional totals row.
Building a table from a related list
Every table in a Dochly template is connected to a related list on the record being generated — for example, Opportunity Line Items on an Opportunity, or Contacts on an Account. You choose the related list once when you build the table, then map each column to a field on those related records.
When the document generates, Dochly reads every record currently in that related list and renders one row per record, in the column layout you defined. There's no row-by-row decision-making — if a record is in the related list, it appears as a row.
| Product Name | Qty | Unit Price | Total |
|---|---|---|---|
| Enterprise Licence | 10 | £500 | £5,000 |
| Premium Support | 1 | £1,200 | £1,200 |
| Legacy Add-on (Discontinued) | 0 | £0 | £0 |
| Implementation Services | 3 | £800 | £2,400 |
| Internal Tracking Code | 1 | £0 | £0 |
Notice that the discontinued line and the internal tracking code still appear in the table above — the table itself has no way to exclude them. If a related list contains records you don't want on the document, they need to be removed, reassigned, or excluded from that related list in Salesforce before the document is generated — Dochly's table will always render whatever it finds.
Step-by-step: adding a related list table
This example adds a line item table to a quote template, listing every Opportunity Product on the Opportunity being generated.
Insert a table into the template
Open the template in the editor and insert a table element at the point where the line items should appear.
Connect the table to a related list
In the table's properties panel, choose the related list to pull rows from — for example, Opportunity Products on the Opportunity. This tells Dochly which child object to read records from when the document generates.
Map columns to fields
Add a column for each piece of data you want to show — Product Name, Quantity, Unit Price, Total — and map each one to a field on the related object. This column layout is fixed once you save it: it applies the same way to every row and every generated document.
Save and preview with a real Opportunity
Save the template, then preview using an Opportunity that has several products attached. Confirm one row appears per product, with the correct value in each column. Whatever records exist in the related list at generation time is exactly what appears in the table — there's no filtering step to check.
Column fields come from the related list record, not the parent record. In an Opportunity Products table, the fields available for columns are on the OpportunityLineItem object. In a Contacts table on an Account, the fields come from the Contact object. If you need a parent field displayed in the table, add a formula field on the child object that copies the parent value, and map a column to that formula field.
Columns are fixed, not conditional
The set of columns in a table is defined once, when you build the table, and it does not change based on the data in any particular record. Every column you add appears in every generated document that uses that template — whether or not a given row has meaningful data for that column.
There is no option to hide a column when it isn't relevant to a specific deal, customer, or record type. If a column has nothing to show for a row, the cell simply renders blank (or shows the field's default value) rather than the column disappearing.
Since the column set can't change per record, the usual approach is to maintain a separate template with a different column layout for the cases where a column genuinely shouldn't appear — for example, one quote template for negotiated pricing (with a Discount column) and one for standard pricing (without it) — and choose the right template when generating the document.
A single table that shows or hides a column automatically based on a field value (e.g. "only show Discount when a discount applies") is not something the table element supports today.
Cell content is a direct field mapping
Each cell in a table row displays the value of the single field it's mapped to for that row — nothing more. There is no if/else logic inside a table cell, so a cell can't switch between two different pieces of content (for example, showing a price for one line type and the word "Included" for another) based on other data in the row.
Formatters that transform a single value — such as displaying a number as currency, or a date in a particular format — are supported on a cell's mapped field. What isn't supported is branching logic that changes which field, or which wording, appears based on a condition.
If your related list mixes row types that genuinely need different content per column (for example, products that should show a price and services that should show "Included"), the table itself can't make that distinction per row. Consider separate fields on the child object that already contain the display-ready value (so the mapping is still a direct one field → one cell relationship), or a separate table/template for each row type.
When a related list has no records
If the related list connected to a table has no records at all, the table still renders its header row, with no data rows beneath it. There is no built-in "no records" message, no variable that reports the row count, and no way to conditionally hide the whole table when it would otherwise be empty.
This is a known limitation, not a configurable option: if a template includes a table and the record being generated has no related records for that table, the generated document will show a header with no rows beneath it. Preview your templates against a record with an empty related list before relying on them, so you know what that document looks like and can decide whether it's acceptable for your use case.
Totals and summary rows
The table element doesn't calculate or conditionally display totals, subtotals, discount lines, or tax lines — it only lists rows from the related list in fixed columns. There's no aggregate function inside the table and no way to add a summary row that appears or changes based on a condition.
If a document needs a total, subtotal, or tax figure, calculate it in Salesforce — for example with a rollup summary field or a formula field on the parent record — and place that value as a regular merge field in the document, outside the table structure. Whether that merge field (or the paragraph containing it) appears at all can be controlled with a section-level show/hide condition or if/else logic — see Show or hide sections and Use if/else conditions — but that logic applies to a block of content next to the table, not to a row inside it.
Pattern library
Common, supported ways to use the table element. None of these rely on row, column, or cell conditions — they work because the underlying related list already contains the right records and fields.
List all Opportunity Products on a quote
Connect the table to the Opportunity Products related list, with columns for Product Name, Quantity, Unit Price, and Total. Every product line on the Opportunity appears as a row. If you don't want a particular line on the quote, remove it from the Opportunity before generating the document.
List related Contacts on an Account document
Connect the table to the Contacts related list on the Account, with columns for Name, Title, Email, and Phone. Every Contact linked to the Account appears as a row — useful for account summaries or onboarding packs.
Use separate templates when the column set genuinely differs
Since a single table can't change its columns based on data, maintain two template versions — for example, a standard quote template and a negotiated-pricing quote template with an extra Discount column — and pick the appropriate one when generating the document.
Show a subtotal, tax, and grand total beneath the table
Add a rollup summary or formula field on the parent record (Opportunity, Invoice, etc.) for each total you need, then place those as merge fields in a paragraph below the table — not inside it. Use a section-level condition if a particular total line (like tax) should only appear for some records.
Frequently asked questions
You now know exactly what a Dochly table can and can't do: it lists every record from a connected related list in a fixed set of columns, with no per-row, per-column, or per-cell logic. Next in this series: Conditional formatting in Dochly — what's actually supported today for adapting a document's appearance and content.
Not on AppExchange yet — contact us and we'll set you up