Reports authored in Word or PowerPoint
A report does not have to be an HTML page. It can be a real .docx or .pptx — written in Word or
PowerPoint, by whoever normally writes the document — with {{ }} placeholders in it. The engine
fills them in and hands back the file.
This guide is that route end to end. Authoring a report is the HTML one, and most of what it says about projects, assets and codes is true here too.
Which kind of report to write
Two kinds, one engine, and the choice is made once when the report is created.
| HTML report | Word or PowerPoint template | |
|---|---|---|
| Written in | HTML, CSS and JS, in the designer | Word, or PowerPoint |
| Laid out by | a browser | Word, or PowerPoint |
| Produces | PDF, Word, PowerPoint or Excel | the one file it is written in |
| Best at | dashboards, precise layout, anything visual | documents people already have, and already maintain |
Pick the office route when the document already exists. A statement, a contract, a certificate, a board deck — something a finance or legal team wrote, formats to their own standard, and expects to keep editing. Nobody has to rebuild it as HTML, and the people who own it keep owning it.
Pick HTML when the layout is the product. A dashboard of cards and charts is a browser's job. And if the report must come out as a PDF, it has to be an HTML report — see What it produces.
The rest of the engine does not change. Your application still calls
GenerateAsync(code, json). Same catalog, same licence, same integrity hashes, same cache. Only
the folder's contents differ.
The folder
An office template report is a folder like any other, named after the report code:
R-acme-erp-004/
template.docx the report — or template.pptx
manifest.json what the engine reads about it
assets/ fonts, stylesheets, chart libraries
parts/ HTML pages the document draws its pictures from
No p1.html, and no page setup. The document carries its own — page size, margins, headers,
footers, section breaks, whatever its author set in Word. That is the point of authoring one.
The language is the same Handlebars
Not a dialect, and not a second template language. Same binder, same helpers, same paths. Anything
true of {{ }} in a template.html is true of {{ }} in a template.docx.
{{customer.name}} a path
{{#each lines}}{{name}}{{/each}} a block
{{#if overdue}}Late{{else}}Due{{/if}} a choice
{{../company.name}} the scope above this one
{{@index}} where you are in the loop
Every helper in Template helper reference works here — money, date, number, the comparisons,
the logic. One exception: {{json}} writes a payload into an HTML data island for chart code to
read, and a document has neither, so it simply prints the JSON as text.
Word breaks your placeholders up and it does not matter. As you type, Word splits a run
wherever it likes — spellcheck, a revision mark, where the cursor happened to be — so {{amount}}
is often three fragments on disk. The engine puts them back together before binding. Nothing to do,
and nothing you could have done: Word never shows you this.
Where a marker may go
Three places, and only three.
| Place | Example | |
|---|---|---|
| In the text | a paragraph, a table cell, a text box | the ordinary case |
| A picture's alt text | {{paragonPart 'chart'}} |
the picture is replaced |
| A shape's alt text | {{paragonFill colour}} |
slides only |
Alt text is reached through Format → Alt Text on the picture or shape.
Never inside an attribute — not a fill colour, not a width, not a style id. Those fields are typed, so a placeholder in one is not a template with a marker in it, it is a broken file. PowerPoint notices and offers to repair the deck, and repairing strips the marker out. Word says nothing at all and silently drops it, which is worse. To colour something from data, see Colour from data.
Alt text is the exception because it is the one string Word and PowerPoint carry through a round trip without validating, reformatting or discarding.
Word
| Marker | Where it goes | What it does |
|---|---|---|
{{field}} |
in the text | Fills in the value |
{{#each items}} … {{/each}} |
both markers in one table row | Repeats that row, once per item |
{{#each items}} … {{/each}} |
each marker alone in its own paragraph | Repeats the paragraphs between them |
{{#if x}} … {{else}} … {{/if}} |
both markers in one run of text | An inline choice between two pieces of text |
{{#if x}} … {{else}} … {{/if}} |
markers in different rows | Chooses between whole rows — this is how a row is shaded by a condition |
{{paragonPart 'name'}} |
a picture's alt text | Renders parts/name.html and drops the result in at the picture's size |
{{field}} |
a picture's alt text | Replaces the picture with an image the payload carries as base64 |
{{pageBreak}} |
in the text | A page break |
A block repeats the smallest thing that holds both of its markers. Put {{#each lines}} and
{{/each}} in the first and last cell of one row and the row repeats. Put each on a paragraph of
its own and the paragraphs between them repeat. That one rule is the whole of it, and nesting,
{{else}}, {{@index}} and ../ all fall out of it, because Handlebars is doing the work.
PowerPoint
Everything above applies, in the same words. These are the things a slide adds.
| Marker | Where it goes | What it does |
|---|---|---|
{{#slides items}} |
anywhere on the slide, or in the slide's notes | Repeats the whole slide, once per item. No closing marker — the slide is the scope. An empty list removes the slide |
{{paragonFill field}} |
a shape's alt text | Colours the shape from the payload. Six hex digits, no # |
{{paragonPart 'name'}} |
a picture's alt text | As in Word — and on a repeated slide it is given that slide's item, so a chart per region draws its own region |
A repeating slide is usually the reason to build a deck from data at all — a slide per region,
per customer, per line. Inside one, that item is the context, so the slide says {{name}} and
still reaches the payload's root through {{../company.name}}. The copies keep their place, so the
slides around them do not move.
Writing the marker in the slide's notes keeps an instruction off a slide that should not carry one.
Colour from data
| A shape on a slide | {{paragonFill field}} in its alt text |
| A Word table cell, with a fixed set of states | Draw the row once per state, style each one in Word, and wrap the set in {{#if}}/{{else}} — the markers land in different rows, so the block picks a row |
| A Word table cell, colour straight from the data | Not supported — a cell's shading is an attribute, and the rule above applies |
| Anything richer | A web part, which is HTML and CSS and can do whatever those can |
paragonFill leaves a real colour on the shape. Fill it in PowerPoint the way it should look — that
is what the template shows its author — and the payload replaces it when the report is built.
Web parts
The parts/ folder holds ordinary HTML pages. A picture whose alt text is {{paragonPart 'name'}}
is replaced by parts/name.html, rendered in a browser and photographed at exactly the size the
picture occupies. That is how a chart gets into a document Word could not have drawn.
The page is bound before it is rendered, so it reads the payload the same way the document does:
<script id="report-data" type="application/json">{{json this}}</script>
<script>
var data = JSON.parse(document.getElementById('report-data').textContent);
</script>
Reference CSS and JS from the report's assets/ folder as any page would. Nothing is fetched from
the internet — the same rule as everywhere else in Paragon.
A part that draws asynchronously needs the same treatment as a chart on an HTML page: see Waiting for several asynchronous things.
What it produces
The file it is written in, and nothing else. A Word template gives a .docx; a PowerPoint
template gives a .pptx. Not a PDF, and not each other.
That is a real limit and worth stating plainly: turning a .docx into a PDF needs Word or
LibreOffice installed on the machine doing it, and Paragon deliberately depends on neither. A report
that has to be a PDF is written as an HTML report, which has always produced all four formats.
Shipping it
Two buttons in the designer that are easy to confuse, because they hand back different things.
Download gives you the document alone — the file to open in Word, edit, and put back with Replace. That is the authoring round trip.
Export gives you the folder as a zip: the document, manifest.json, assets/ and parts/.
That is what a consuming application needs. Unzip it into the application's template folder and the
report is deployed — see Quick start for a consuming application.
The document travels byte for byte. Nothing rewrites it on the way out, so what you shipped is the file you last saved.
Things that will not work
A block marker typed between paragraphs. Give each marker a line of its own. Written loose between paragraphs on a slide, it is text in a place the format does not allow text, and PowerPoint will refuse to open the file. Word tolerates the same mistake, so it usually shows up on the deck first.
Literal {{ }} in prose. An empty pair is an expression Handlebars cannot compile, and a real
pair is a placeholder rather than a description of one. A template that documents its own syntax to
its reader has to say it in words.
A placeholder in a fill colour, a width or a style id. See Where a marker may go.
A PDF, or a deck out of a document. See What it produces.
When it fails
The four above are mistakes in the template: they produce a file that opens wrong, or does not open, rather than an error you can catch. These are the ones raised as exceptions.
| Condition | Exception |
|---|---|
The template file is not a readable .docx or .pptx — truncated, or never an Office file |
InvalidOfficeTemplateException (the SDK's own error is the inner exception) |
| A readable package with no document part, or no presentation part | InvalidOfficeTemplateException |
| The manifest says Word or PowerPoint and no template file was loaded | OfficeTemplateMissingException (carries ReportCode and Format) |
A {{paragonPart 'name'}} with no parts/name.html in the folder |
MissingWebPartException (carries Name and the Path it looked for) |
All derive from ParagonException, so one catch still covers the route.
Everything that happens before the template is opened — the folder, the manifest, the assets — fails
the same way it does for an HTML report, and those are in
Report template format — schema 1.0. A marker that names a helper the engine does not have
raises TemplateBindingException here exactly as it does on a page; see Template helper reference.
The worked examples
Three of them among the worked examples, and each is the real file — download it and open it in Word or PowerPoint.
| Customer Account Statement | A Word statement: a looped table, rows shaded by condition, and two web parts side by side |
| Biography | A Word document at its plainest — paths, a loop over paragraphs, and a picture from the payload |
| Quarterly Business Review | A deck using every slide marker, left visible on the slides on purpose |