Example Quote Template
This page brings everything together in a complete quote template. It uses the example quote from the Data Reference: a welding robot configuration with a BoM price table, a discounts table, commercial terms and product images.
You can use it in two ways: upload the HTML version as-is and adjust the styling, or use the Word blueprint to build the same quote in Word.
What the template produces
| Section | Source in the data |
|---|---|
| Logo, quote number, customer and dates | d.id, d.revision_number, d.name, d.email, d.created_at, d.user |
| Price table grouped by Essentials, Software, Accessories, … | d.form_submissions[0].form.bom.tables[0] |
| Discount lines with total discount (removed when there are no discounts) | d.form_submissions[0].form.bom.tables[label='Discounts'] |
| Grand total | d.form_submissions[0].form.bom.summary |
| Commercial terms with a fallback text | d.extra_fields[name='Commercial Terms'].fields |
| Product details page with image and description | d.form_submissions[0].form.data.elements[].options[] |
HTML template
-
Download the template or copy the code below into a file called
quote-template.html. -
Replace the logo URL with the URL of your own logo, and adjust colours and fonts in the
<style>block. -
If your BoM tables have different names, change
tables[0]andtables[label='Discounts']to match your BoM Builder setup. ChangeCommercial Termsto the name of your request field tab. -
Upload the file in Settings → Document Templates and generate a quote to test it.
<!DOCTYPE html><html lang="{d.languageSlug}"><head> <meta charset="utf-8"> <title>Quote {d.id}-{d.revision_number}</title> <style> body { font-family: Arial, sans-serif; font-size: 11px; color: #1f2933; margin: 0; } h1 { font-size: 22px; margin: 0 0 4px; } .muted { color: #6b7280; } .header { display: flex; justify-content: space-between; margin-bottom: 24px; } table { width: 100%; border-collapse: collapse; margin-bottom: 16px; } th { text-align: left; border-bottom: 2px solid #1f2933; padding: 6px 4px; } td { padding: 5px 4px; border-bottom: 1px solid #e5e7eb; vertical-align: top; } .group td { background: #f3f4f6; font-weight: bold; } .num { text-align: right; white-space: nowrap; } .center { text-align: center; } .total td { font-weight: bold; border-top: 2px solid #1f2933; border-bottom: none; } .description { white-space: pre-line; } .logo { height: 40px; margin-bottom: 16px; } .page-break { page-break-before: always; break-before: page; } </style></head><body>
<!-- Replace with the URL of your own logo --> <img class="logo" src="https://yourcompany.com/logo.png" alt="Logo">
<div class="header"> <div> <h1>{d.languageSlug:ifEQ('da'):show('Tilbud'):elseShow('Quote')} {d.id}-{d.revision_number}</h1> <div class="muted">{d.configuration_name}</div> </div> <div> <div><strong>{d.name}</strong></div> <div>{d.email}</div> <div class="muted">Date: {d.created_at:formatD('DD-MM-YYYY')}</div> <div class="muted">Valid until: {d.created_at:addD(30, 'day'):formatD('DD-MM-YYYY')}</div> <div class="muted">Your contact: {d.user.name} ({d.user.email})</div> </div> </div>
<!-- Price table from the BoM: one heading row per group, one row per option --> <h2>{d.form_submissions[0].form.bom.tables[0].label}</h2> <table> <thead> <tr> <th>{d.form_submissions[0].form.bom.tables[0].headerColumns[i].label}</th> <th>{d.form_submissions[0].form.bom.tables[0].headerColumns[i+1].label}</th> </tr> </thead> <tbody> <tr class="group"> <td colspan="3">{d.form_submissions[0].form.bom.tables[0].groups[i].label}</td> </tr> <tr> <td>{d.form_submissions[0].form.bom.tables[0].groups[i].rows[i].optionRows[i].optionColumns[field='name'].value}</td> <td class="center">{d.form_submissions[0].form.bom.tables[0].groups[i].rows[i].optionRows[i].optionColumns[field='sku'].value}</td> <td class="num">{d.form_submissions[0].form.bom.tables[0].groups[i].rows[i].optionRows[i].optionColumns[field='sales_price'].value}</td> </tr> <tr><td>{d.form_submissions[0].form.bom.tables[0].groups[i].rows[i].optionRows[i+1]}</td></tr> <tr><td>{d.form_submissions[0].form.bom.tables[0].groups[i].rows[i+1]}</td></tr> <tr><td>{d.form_submissions[0].form.bom.tables[0].groups[i+1]}</td></tr> </tbody> </table>
<!-- Removed automatically when the quote has no discounts --> <table> <thead> <tr> <th colspan="2">Discounts{d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows:ifEM():drop(table)}</th> </tr> </thead> <tbody> <tr> <td>{d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows[i].label}</td> <td class="num">{d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows[i].optionRows[0].optionColumns[field='sales_price'].value}{d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows[i].subtotals[field='sales_price'].value}</td> </tr> <tr><td>{d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows[i+1]}</td></tr> </tbody> </table>
<table> <tbody> <tr class="total"> <td>{d.form_submissions[0].form.bom.summary.rows[i].label}</td> <td class="num">{d.form_submissions[0].form.bom.summary.rows[i].value}</td> </tr> <tr><td>{d.form_submissions[0].form.bom.summary.rows[i+1]}</td></tr> </tbody> </table>
<h2>Commercial terms</h2> <table> <tbody> <tr> <td>{d.extra_fields[name='Commercial Terms'].fields[i].name}</td> <td class="description">{d.extra_fields[name='Commercial Terms'].fields[i].value:ifEM():show('To be agreed')}</td> </tr> <tr><td>{d.extra_fields[name='Commercial Terms'].fields[i+1]}</td></tr> </tbody> </table>
<!-- Product details with images: only options that have an image --> <div class="page-break"></div> <h2>Product details</h2> <table> <tbody> <tr> <td style="width: 120px;"><img src="{d.form_submissions[0].form.data.elements[i].options[i, image!=''].image}" style="width: 110px; height: auto;"></td> <td> <strong>{d.form_submissions[0].form.data.elements[i].options[i, image!=''].label}</strong> <div class="description">{d.form_submissions[0].form.data.elements[i].options[i, image!=''].description}</div> </td> </tr> <tr><td>{d.form_submissions[0].form.data.elements[i].options[i+1, image!='']}</td></tr> <tr><td>{d.form_submissions[0].form.data.elements[i+1]}</td></tr> </tbody> </table>
</body></html>Word blueprint
To build the same quote in Word, create the following blocks. Each table below represents a Word table; each line in a cell is a paragraph.
1. Header
Put your logo in the Word header. In the body, add:
{d.languageSlug:ifEQ('da'):show('Tilbud'):elseShow('Quote')} {d.id}-{d.revision_number}{d.configuration_name}
{d.name}{d.email}Date: {d.created_at:formatD('DD-MM-YYYY')}Valid until: {d.created_at:addD(30, 'day'):formatD('DD-MM-YYYY')}Your contact: {d.user.name} ({d.user.email})2. Price table
A table with three columns and five rows. Style row 2 as a group heading (for example bold with a grey background) and row 3 as a normal product row. Rows 4 to 6 are removed from the output, so their style doesn’t matter.
| Row | Description | Article No. | Sales price |
|---|---|---|---|
| 1 | Description | Article No. | Sales price |
| 2 | {d.form_submissions[0].form.bom.tables[0].groups[i].label} | ||
| 3 | {d.form_submissions[0].form.bom.tables[0].groups[i].rows[i].optionRows[i].optionColumns[field='name'].value} | {d.form_submissions[0].form.bom.tables[0].groups[i].rows[i].optionRows[i].optionColumns[field='sku'].value} | {d.form_submissions[0].form.bom.tables[0].groups[i].rows[i].optionRows[i].optionColumns[field='sales_price'].value} |
| 4 | {d.form_submissions[0].form.bom.tables[0].groups[i].rows[i].optionRows[i+1]} | ||
| 5 | {d.form_submissions[0].form.bom.tables[0].groups[i].rows[i+1]} | ||
| 6 | {d.form_submissions[0].form.bom.tables[0].groups[i+1]} |
3. Discounts table
A table with two columns. The tag in row 1 removes the whole table when there are no discounts. Row 3 is for subtotals and can be styled in bold.
| Row | Description | Discount |
|---|---|---|
| 1 | Discounts {d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows:ifEM():drop(table)} | |
| 2 | {d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows[i].label} {d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows[i].type:ifEQ('subtotal'):drop(row)} | {d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows[i].optionRows[0].optionColumns[field='sales_price'].value} |
| 3 | {d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows[i].label} {d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows[i].type:ifNE('subtotal'):drop(row)} | {d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows[i].subtotals[field='sales_price'].value} |
| 4 | {d.form_submissions[0].form.bom.tables[label='Discounts'].groups[0].rows[i+1]} |
4. Total
{d.form_submissions[0].form.bom.summary.rows[0].label}: {d.form_submissions[0].form.bom.summary.rows[0].value}5. Commercial terms
| Row | Term | Value |
|---|---|---|
| 1 | {d.extra_fields[name='Commercial Terms'].fields[i].name} | {d.extra_fields[name='Commercial Terms'].fields[i].value:ifEM():show('To be agreed'):convCRLF} |
| 2 | {d.extra_fields[name='Commercial Terms'].fields[i+1]} |
6. Product details
Start this block on a new page. Insert a placeholder image (set to In line with text) in the first cell and put the tag from the table below in its alternative text.
| Row | Image | Product |
|---|---|---|
| 1 | placeholder image, alt text: {d.form_submissions[0].form.data.elements[i].options[i, image!=''].image:imageFit(contain)} | {d.form_submissions[0].form.data.elements[i].options[i, image!=''].label} {d.form_submissions[0].form.data.elements[i].options[i, image!=''].description:convCRLF} |
| 2 | {d.form_submissions[0].form.data.elements[i].options[i+1, image!='']} | |
| 3 | {d.form_submissions[0].form.data.elements[i+1]} |
Result
Generated with the example quote, the price section looks like this:
Quote 2586-1 Jane DoeProject name jane.doe@example.com Date: 17-09-2026 Valid until: 17-10-2026 Your contact: Alex Seller (alex@yourcompany.com)
CoWelder QuoteDescription Article No. Sales priceEssentialsUR12e 36940412 398,870.00 krSelect 400 SV Synergic DC 1.0V 79542563 78,050.00 krAB ROB W500 22gr, 36072505 28,440.00 krSoftwarePulse Function 10682002 7,650.00 krPowerArc 10682003 2,450.00 krPowerArc Pulse 10682005 6,040.00 krSequence Repeat 10683002 1,300.00 krWeaving 10950000 25,840.00 krOffset 10950010 13,300.00 krAccessoriesWear Parts Box - W500 - 1.2mm 81100260 2,870.00 krTorch bundle - ABIROB® W5F 36072508 13,760.00 krUR12E/8L KIT FOR 3PE 45050547 2,830.00 krServicesBasic Training Package 99906111 9,680.00 krFreightDelivery incl. packaging - Basic - DK - Zone 1 Basic_DK_1 3,761.00 kr
DiscountsSoftware discount -28,290.00 krAdditional Discount -50,000.00 krTotal discount -78,290.00 kr
Total price 516,551.00 kr
Commercial termsWarranty To be agreedPayment To be agreedDelivery To be agreedDelivery Conditions To be agreedIdeas to extend the template
- Add a QR code with the quote number:
{d.id:barcode(qrcode)}. See QR codes and barcodes. - Show a savings banner when the discount is large. See Storing results.
- Let sales users choose the layout in the configurator. See Layout switches.
- Translate the headings for Danish quotes. See Language-dependent text.