DEV Community

Cover image for Cheat Sheet for Carbone
Steeve for Carbone

Posted on

Cheat Sheet for Carbone

Carbone is a templating engine designed to generate dynamic documents (PDFs, DOCX, XLSX, PPTX, etc.) by merging templates with JSON data:

  • The JSON Data-set coming from your application, database, or API.
  • The template must be designed using a Text Editor like Word, LibreOffice or Google Docs. To inject the content dynamically you must write Tags (a.k.a. placeholder), it will be replaced with the corresponding values from the JSON data.

Carbone Templating Syntax Cheat Cheet

Carbone’s tag syntax offers a lot of possibilities! This article focuses on the essentials, but if you want to dive deeper or see more examples, check out the official documentation.

Essential Carbone Templating Syntax

1. Basic Placeholder

The placeholder tag injects the value of a property from the root of the JSON data object (d). It is the simplest way to insert dynamic data into your template. For instance, if the JSON dataset is:

{ 
  "firstname": "John"
}
Enter fullscreen mode Exit fullscreen mode

Insert the following tag in the template:

{d.firstname}
Enter fullscreen mode Exit fullscreen mode

and it will be replaced with "John" in the generated document.

2. Nested Placeholder

This tag accesses nested properties in the JSON data. It allows you to traverse deeper into the JSON structure to retrieve specific values. There is no limit to access in depth of nested properties. For instance, If your JSON is:

{
  "user": {
    "name": "Alice"
  }
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template file:

{d.user.name}
Enter fullscreen mode Exit fullscreen mode

will be replaced with "Alice".

3. Access Parent Property

The double dot (..) notation lets you access a property of the parent object from a nested context. To access the grandparent object’s property, use three dots (...). You can chain as many dots as needed to navigate up the object hierarchy. If your JSON is:

{
  "country": "France",
  "movie": {
    "name": "Inception", 
    "sub": {
      "a" : "test"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

{d.movie.sub..name}
{d.movie.sub...country} 
Enter fullscreen mode Exit fullscreen mode

The first tag will be replaced with "Inception".
The second tag will be replaced with "France"

4. Array Access with Static Index

This tag accesses a specific element in an array by its index using the square bracket notation [index]. It is useful for retrieving a particular item from an array without looping. If your JSON is:

{
  "movies": [
    { "name": "Inception" },
    { "name": "Matrix" }
  ]
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

{d.movies[0].name}
Enter fullscreen mode Exit fullscreen mode

will be replaced with "Inception".

5. Conditional Logic

This tag uses the :ifEQ formatter to check if a value meets a specific condition. If the condition is met, it prints the specified text. It exists many conditional formatters (e.g. :ifIN, :ifGT, etc...), and it can be chained (using :and, :or) for complex logic and used in inline conditions, or conditional sections. If your JSON is:

{
  "isActive": true
  "message": "Your subscription is disabled."
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

{d.isActive:ifEQ(true):show('Yes'):elseShow(.message)}
Enter fullscreen mode Exit fullscreen mode

will be replaced with the static text "Yes" if the value is true, otherwise the value of the "message" field is printed.

6. Default Value

Still using conditional formatters, the :ifEM formatter checks if a value is empty (null, undefined, empty string, empty array, or empty object). If it is, it prints the specified default value. If your JSON is:

{
  "user": {
    "name": null
  }
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

{d.user.name:ifEM:show('Unknown')}
Enter fullscreen mode Exit fullscreen mode

will be replaced with the static text "Unknown".

7. Loop (Array Iteration)

Use the square bracket notation [i] to iterate over arrays, The character i is the loop iterator (automatically managed by Carbone). Then insert the [i+1] tag, which signals the end of the pattern and is automatically removed during rendering.

This allows you to repeat content for each item in an array. If your JSON is:

{
  "users": [
    { "id": 1, "name": "Alice", "role": "Admin" },
    { "id": 2, "name": "Bob", "role": "Editor" },
    { "id": 3, "name": "Charlie", "role": "Viewer" }
  ]
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

{d.users[i].id} - {d.users[i].name}
<!-- End of loop pattern -->
{d.users[i+1]}

Enter fullscreen mode Exit fullscreen mode

will print each user's id and name in a new line.

Note: You do not need to repeat each [i] tag with [i+1], just the one [i+1] is enough for Carbone to recognize the loop pattern.

8. Loop of Nested Arrays

Use the square bracket notation [i] and [i+1] (explained the previous point) to iterate over arrays, including nested ones. You can nest loops as deeply as needed. Finally, always use i as the loop iterator, even for nested arrays: Do not ever use "j" or other characters. If your JSON is:

[
  {
    "brand": "Toyota",
    "models": [
      { "size": "Prius 4", "power": 125 },
      { "size": "Prius 5", "power": 139 }
    ]
  },
  {
    "brand": "Kia",
    "models": [
      { "size": "EV4", "power": 450 },
      { "size": "EV6", "power": 500 }
    ]
  }
]
Enter fullscreen mode Exit fullscreen mode

The tags loops in the template:

{d[i].brand}
Models
{d[i].models[i].size} - {d[i].models[i].power}
{d[i].models[i+1]}
{d[i+1]}
Enter fullscreen mode Exit fullscreen mode

Will generate the following content:

Toyota
Models
Prius 4 - 125
Prius 5 - 139
Kia
Models
EV4 - 450
EV6 - 500
Enter fullscreen mode Exit fullscreen mode

9. Filter a Loop

In a loop, it is possible to filters Arrays to only include items that meet a specific condition. Only matching items are printed in the loop. You can add as many conditions as you want, based on the attributes in your list. To filter an array, use the following syntax in your loop tag:

{d.array[i, condition1, condition2, ...]}
Enter fullscreen mode Exit fullscreen mode

If you have the following JSON:

{
  "items": [
    {"name": "Strawberries", "price": 268, "category": "fruit"},
    {"name": "Apple", "price": 50, "category": "fruit"},
    {"name": "Banana", "price": 150, "category": "fruit"},
    {"name": "Carrot", "price": 80, "category": "vegetable"}
  ]
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

{d.items[i, price > 100, category="fruit"].name}
{d.items[i+1, price > 100, category="fruit"]}
Enter fullscreen mode Exit fullscreen mode

will only print "Strawberries" and "Banana". The loop prints items where the price is greater than 100 and the category is "fruit".

10. Sort a Loop

In a loop, it is possible to sorts Array by a one or multiple attributes before iterating over it. The array will be sorted in ascending order based on the first attribute, then by the second attribute if values are equal, and so on. The syntax is:

{d.array[attribute1, attribute2, ..., i]}
Enter fullscreen mode Exit fullscreen mode

If your JSON is:

{
  "items": [
    {"name": "Apple", "power": 2},
    {"name": "Banana", "power": 1}
  ]
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

{d.items[power, i].name}
{d.items[power+1, i+1].name}
Enter fullscreen mode Exit fullscreen mode

will print "Banana" followed by "Apple". You can specify as many attributes as you want (e.g., power, name, etc.).

Important note: while sorting, the i iterator must always be the last element in the squared brackets.

11. Formatters

Formatters are functions appended to tags with a colon (:) that modify data before display. They can accept static or dynamic parameters.

11.1 Text Formatters

These formatters transform text in various ways, such as changing case, extracting substrings, replacing text, and more.

Formatter Description Example
:lowerCase() Converts text to lowercase {d.name:lowerCase()}
:upperCase() Converts text to uppercase {d.name:upperCase()}
:substr(start, length) Extracts a substring {d.text:substr(0, 5)}
:replace(search, replace) Replaces text {d.text:replace('old', 'new')}
:len() Returns the length of a string or array {d.text:len()}
:convCRLF() Converts line breaks to <br> {d.text:convCRLF()}
:preserveCharRef() Preserves character references {d.text:preserveCharRef()}
:t Translates text (Learn more on the dedicated section below) {d.greeting:t}

11.2 Number Formatters

These formatters format numbers, including setting precision, rounding, and performing arithmetic operations.

Formatter Description Example
:formatN(decimals) Formats with the specified number of decimal places. {d.price:formatN(2)}
:round(decimals) Rounds with the specified number of decimal places. {d.value:round(2)}
:floor() Rounds down to the nearest integer. {d.value:floor()}
:ceil() Rounds up to the nearest integer. {d.value:ceil()}
:add(value) Adds a value {d.value:add(10)}
:sub(value) Subtracts a value {d.value:sub(10)}
:mul(value) Multiplies by a value {d.value:mul(2)}
:div(value) Divides by a value {d.value:div(2)}
:mod(value) Modulo operation {d.value:mod(2)}
:abs() Absolute value {d.value:abs()}

11.3 Currency Formatters

These formatters format numbers as currency, including setting precision and converting between currencies.

Formatter Description Example
:formatC(precision, currency) Formats a number as currency {d.price:formatC(2, 'USD')}
:convCurr(source, target) Converts currency {d.price:convCurr('EUR', 'USD')}

11.4 Date Formatters

These formatters format dates according to specified patterns.

Formatter Description Example
:formatD(pattern) Formats a date {d.date:formatD('YYYY-MM-DD')}
:formatI(pattern) Formats an interval {d.interval:formatI('HH:mm')}

11.5 Array Formatters

These formatters manipulate arrays, such as joining elements, and mapping values, and performing aggregations (Process a set of values and returns a single aggregated result).

Formatter Description Example
:arrayJoin(separator) Joins array elements {d.array:arrayJoin(', ')}
:arrayMap(separator, keySeparator, key) Maps array elements {d.array:arrayMap(', ', ':', 'id')}
:aggStr(separator) Aggregator to concatenate array elements {d.array[].value:aggStr(', ')}
:aggSum() Aggregator to sums array elements {d.array[].value:aggSum()}
:aggAvg() Aggregator to get the average {d.array[].value:aggAvg()}
:aggMin() Aggregator to get the minimum value {d.array[].value:aggMin()}
:aggMax() Aggregator to get the maximum value {d.array[].value:aggMax()}
:aggCount() Aggregator that return the total number of elements {d.cars[sort>20].qty:aggCount}
:cumSum() Aggregator for running totals: Calculates and prints the cumulative sum of data {d[i].qty:cumSum} {d[i+1]}
:cumCount() Aggregator that print a sequential integer to each row in a list. {d[i].qty:cumCount} {d[i+1]}

12. Colors

The :color formatter lets you dynamically apply colors to text, paragraphs, cells, rows, or shapes in your templates. You specify the target element and the color value from your JSON data. The syntax is:

{d.colorValue:color(scope, types)}
Enter fullscreen mode Exit fullscreen mode

If your JSON is:

{
  "warningHexa": "#FF0000",
  "highlightHexa": "#FFFF00"
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

<!-- For Text --> 
{d.warningHexa:color(p)}This text will be red.
<!-- For Tables -->
{d.highlightHexa:color(cell, background)}This cell will have a yellow background.
Enter fullscreen mode Exit fullscreen mode

will color the text "This text will be red." in red and the cell background of "This cell will have a yellow background." in Yellow.

13. Inject HTML from WYSIWYG or Code Editors

The :html formatter allows you to inject raw HTML strings from your JSON data directly into your template (supported formats: DOCX, ODT and PDF). Without this formatter, "<" and ">" characters are escaped, and HTML is not rendered. If your JSON is:

{
  "welcomeMessage": "<strong>Welcome!</strong> Here’s your dashboard."
}
Enter fullscreen mode Exit fullscreen mode

The tag in the DOCX template:

{d.welcomeMessage:html}
Enter fullscreen mode Exit fullscreen mode

the welcome message is injected, and the HTML is rendered in the generated document.

14. Merge PDFs

The :appendFile(position) formatter lets you dynamically insert a PDF into your generated PDF document. The file can be provided as a Base64 string or a URL in your JSON data. If your JSON data is:

{
  "contractPDF": "base64EncodedPdfFile",
  "links": {
    "welcomePDF": "https://domain/welcome.pdf"
  }
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

{d.links.welcomePDF:appendFile(start)}
{d.contractPDF:appendFile(end)}
Enter fullscreen mode Exit fullscreen mode

15. Images

To inject images dynamically, a placeholder image must be defined in the template with the tag as alternative text. Then Carbone will replace the placeholder images with images specified in your JSON data-set. In order you have to:

  1. Insert a placeholder/dummy image in your template.
  2. Place the tag in the alternative text of the placeholder image.
  3. Specify the image in your JSON as either a Base64-encoded string or a URL.

If your JSON data is:

{
  "logoBase64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
  "profilePictureUrl": "https://example.com/profile.jpg"
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

<!-- In the alternative text of an image -->
{d.logoBase64}
Enter fullscreen mode Exit fullscreen mode

will be replaced with the image from your JSON data.

16. Charts

The :chart formatter lets you generate charts using ECharts v5 configuration. Just Insert a placeholder image in your template (DOCX, ODT, etc.), then the tag must be placed in the alternative text of the placeholder image, and finally, chain the tag with the :chart formatter. If your JSON data is:

{
  "salesChart": {
    "type": "echarts@v5",
    "width": 600,
    "height": 400,
    "option": {
      "xAxis": {
        "type": "category",
        "data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
      },
      "yAxis": {
        "type": "value"
      },
      "series": [{
        "data": [150, 230, 224, 218, 135, 147, 260],
        "type": "line"
      }]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

<!-- In the alternative text of an image -->
{d.salesChart:chart}
Enter fullscreen mode Exit fullscreen mode

will render the Echart as SVG image in the generated document.

Important Note: All ECharts configuration options are supported, but external scripts or dependencies are not.

17. Barcodes

It is possible to insert barcodes into your documents using the :barcode(type) formatter. The barcode is rendered as an SVG image and can be embedded directly into your template. The option type is required to define the format of barcode expected. How to Use:

  1. Define the barcode data in your JSON.
  2. Insert a placeholder image in your template.
  3. Place the tag in the alternative text of the placeholder image, chain the :barcode(type) formatter (don't forget the type of barcode as argument).

If you JSON is:

{
  "productCode": "123456789",
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

<!-- In the alternative text of an image -->
{d.productCode:barcode(ean13)}
Enter fullscreen mode Exit fullscreen mode

Will inject a barcode image as SVG in the generated document.

18. Translations

For multi-language documents, static and dynamic translations are supported using localization dictionaries. During rendering, the language must be provided using the lang option in the report configuration. Both static and dynamic translations rely on the same dictionary.

  • Static translation: use {t('key')} to translate static text in your template. The translation is based on the language set in the report options.
  • Dynamic translation: Use the :t formatter to translate dynamic values from your JSON data.

If your JSON is:

{
  "name": "John",
  "status": "pending"
}
Enter fullscreen mode Exit fullscreen mode

AND if the localization dictionary is:

{
  "fr-fr" : { 
    "greeting" : "Bonjour",
    "pending"  : "En cours"
  },
  "en-us" : {
    "greeting" : "Hello",
    "pending"  : "In progress"
  },
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

{t('greeting')} {d.name} 👋
Payment Status: {d.status:t}.
Enter fullscreen mode Exit fullscreen mode

will generate the following document if the selected language is fr:

Bonjour John 👋
Payment Status: En cours.
Enter fullscreen mode Exit fullscreen mode

19. Hyperlinks

For inserting clickable links in document, insert a hyperlink in your template, and set the URL to a Carbone tag, e.g., {d.documentationUrl}, that's it. If your JSON is:

{
  "title": {
    "url": "https://carbone.io/documentation",
    "name": "Documentation"
  }
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template with the hyperlink {d.title.url}:

{d.title.name}
Enter fullscreen mode Exit fullscreen mode

will render in the document the title "My Profile", and redirect to the page https://carbone.io/documentation.

20. Electronic Signatures

Two ways are available to inject signatures in documents:

  • Insert a signature image: using dynamic images.
  • Use a third-party e-signature service: To do this, prepare your document by placing tags with the :sign formatter where you want signatures to appear. If the JSON is:
{
  "signer": {
    "name": "John Doe",
    "email": "john.doe@example.com"
  }
}
Enter fullscreen mode Exit fullscreen mode

The tag in the template:

{d.signer:sign}
Enter fullscreen mode Exit fullscreen mode

will generate a document with the signature position and signer details. This information are used by third-party services like DocuSign, Yousign, Signwell, or Documenso to handle the signature process.

Conclusion

We’ve covered the most important and commonly used syntax of Carbone's templating. You can now automate the creation of contracts, reports, invoices, and other documents in many fields: finance, healthcare, accounting, legal, and science, more!

Feel free to join our Official Discord — it’s a friendly place to connect and get help from the Carbone community.

Enjoy creating stunning documents with Carbone! Cheers 🍻

Top comments (0)