Formatting Values
Values in the quote data are stored in a raw form: prices are plain numbers like 516551, and dates look like 2026-09-17T08:52:37.000000Z. Formatters turn them into something readable.
Add a formatter after the path, separated by a colon. You can chain as many formatters as you like. They are applied from left to right:
{d.name:upperCase}{d.created_at:formatD('DD MMMM YYYY')}{d.conf_total:add(d.vat_total):formatN(2)}Numbers and prices
formatN
formatN(decimals) formats a number with thousands separators and a fixed number of decimals, following the document language:
| Tag | Language | Result |
|---|---|---|
{d.conf_total:formatN(2)} | English (default) | 516,551.00 |
{d.conf_total:formatN(2)} | {o.lang=da-DK} | 516.551,00 |
{d.conf_total:formatN(2)} | {o.lang=de-DE} | 516.551,00 |
{d.conf_total:formatN(0)} | English | 516,551 |
Set the language once for the whole document with an option tag, see Language and time zone.
Prices with a currency
Combine formatN with the currency code of the quote:
Total: {d.conf_total:formatN(2)} {d.currencyCode}Total: 516,551.00 DKKOr put a fixed currency label in front with prepend, or after with append:
{d.conf_total:formatN(2):prepend('DKK ')}{d.conf_total:formatN(2):append(' kr.')}DKK 516,551.00516,551.00 kr.Rounding
| Formatter | Example | Result |
|---|---|---|
round(decimals) | {d.form_submissions[0].form.data.elements[label='Delivery'].options[0].price:div(3):round(2)} | 1253.67 |
ceil | 3761.2 → ceil | 3762 |
floor | 3761.8 → floor | 3761 |
abs | -78290 → abs | 78290 |
Always round before formatN when the result of a calculation should be rounded in a specific way. See Calculations.
Percentages
Discount inputs are stored as plain numbers, for example 50 for 50 %. Add the sign yourself:
Software discount: {d.form_submissions[0].form.data.elements[label='Software discount in %'].value}%If you have a ratio between 0 and 1, multiply it first:
{c.discountRatio:mul(100):round(1)}%Dates
formatD
formatD(pattern) formats a date. All dates in the quote data are in UTC.
| Tag | Result |
|---|---|
{d.created_at:formatD('DD-MM-YYYY')} | 17-09-2026 |
{d.created_at:formatD('DD/MM/YYYY HH:mm')} | 17/09/2026 08:52 (UTC, see Time zone) |
{d.created_at:formatD('D MMMM YYYY')} | 17 September 2026 |
{d.created_at:formatD('dddd D MMMM YYYY'):ucFirst} | Thursday 17 September 2026 |
{d.created_at:formatD('YYYY-MM-DD')} | 2026-09-17 |
{d.created_at:formatD('L')} | 09/17/2026 (English) or 17.09.2026 (Danish) |
{d.created_at:formatD('LL')} | September 17, 2026 (English) or 17. september 2026 (Danish) |
Common pattern tokens:
| Token | Meaning | Example |
|---|---|---|
YYYY / YY | Year | 2026 / 26 |
MMMM / MMM / MM / M | Month name, short name, 2-digit, number | September / Sep / 09 / 9 |
DD / D / Do | Day, 2-digit, number, with suffix | 07 / 7 / 7th |
dddd / ddd | Weekday name, short name | Thursday / Thu |
HH / mm / ss | Hours (24h), minutes, seconds | 08 / 52 / 37 |
h / A | Hours (12h), AM/PM | 8 / AM |
W | ISO week number | 38 |
L / LL / LLL | Short date, long date, long date with time (depends on language) |
Month and weekday names follow the document language set with {o.lang=…}.
Time zone
Dates are stored in UTC. To show local times, set the time zone for the document:
{o.timezone=Europe/Copenhagen}Created: {d.created_at:formatD('DD-MM-YYYY HH:mm')}Created: 17-09-2026 10:52Date calculations
| Formatter | Example | Result |
|---|---|---|
addD(amount, unit) | {d.created_at:addD(30, 'day'):formatD('DD-MM-YYYY')} | 17-10-2026 |
subD(amount, unit) | {d.created_at:subD(1, 'month'):formatD('DD-MM-YYYY')} | 17-08-2026 |
startOfD(unit) | {d.created_at:startOfD('month'):formatD('DD-MM-YYYY')} | 01-09-2026 |
endOfD(unit) | {d.created_at:endOfD('month'):formatD('DD-MM-YYYY')} | 30-09-2026 |
Units: day, week, month, quarter, year, hour, minute, second.
A typical use is a quote validity date:
This quote is valid until {d.created_at:addD(30, 'day'):formatD('D MMMM YYYY')}.This quote is valid until 17 October 2026.Text
| Formatter | Example | Result |
|---|---|---|
upperCase | {d.configuration_name:upperCase} | PROJECT NAME |
lowerCase | {d.email:lowerCase} | jane.doe@example.com |
ucFirst | 'hello world' → ucFirst | Hello world |
ucWords | {d.name:lowerCase:ucWords} | Jane Doe |
prepend(text) | {d.id:prepend('Q-')} | Q-2586 |
append(text) | {d.id:append('-')} | 2586- |
replace(old, new) | {d.form_submissions[0].form.name:replace('V2', '')} | Migatronic CoWelder |
substr(start, end) | {d.currencyCode:substr(0, 2)} | DK |
ellipsis(max) | {d.form_submissions[0].form.data.elements[0].options[0].description:ellipsis(40)} | The basic edition of CoWelder combines a... |
padl(length, char) | {d.id:padl(8, '0')} | 00002586 |
padr(length, char) | {d.id:padr(6, '0')} | 258600 |
len | {d.name:len} | 8 |
print(text) | {d.id:print('Confidential')} | Confidential |
Quote numbers
Build a quote number from several fields:
Quote no. {d.id:padl(6, '0'):prepend('Q-')}-{d.revision_number}Quote no. Q-002586-1Line breaks in descriptions
Option descriptions and text-area request fields can contain line breaks. In Word, use convCRLF to keep them:
{d.form_submissions[0].form.data.elements[label='Solution'].options[0].description:convCRLF}In HTML templates, use the CSS property white-space: pre-line on the element instead. See HTML templates.
Chaining formatters
Formatters are chained, never nested. Each formatter receives the output of the one before it:
Right: {d.conf_total:add(d.vat_total):formatN(2)}Wrong: {d.conf_total:formatN(add(d.vat_total))}Order matters. Calculate first, then format. formatN turns a number into text, so a calculation after it will not work as expected.
Formatter reference
| Category | Formatters |
|---|---|
| Numbers | formatN, round, ceil, floor, abs, add, sub, mul, div, mod |
| Dates | formatD, addD, subD, startOfD, endOfD, diffD |
| Text | upperCase, lowerCase, ucFirst, ucWords, prepend, append, replace, substr, split, ellipsis, padl, padr, len, print, convCRLF, unaccent |
| Lists | arrayJoin, arrayMap, aggStr, aggStrD |
| Conditions | ifEQ, ifNE, ifGT, ifGTE, ifLT, ifLTE, ifIN, ifNIN, ifEM, ifNEM, show, elseShow, drop, keep, showBegin/showEnd, hideBegin/hideEnd |
| Totals | aggSum, aggAvg, aggMin, aggMax, aggCount, aggCountD, cumSum, cumCount |
| Images and codes | imageFit, barcode |
| Storing values | set |