Author Advanced Word Templates
Template Authoring Guide
This guide covers the advanced template authoring techniques for designing robust, dynamic templates directly inside Microsoft Word.
The Word Template Syntax guide should be used as a companion when creating templates, as Build a Doc template syntax is required to generate dynamic documents.
The Build a Doc Word Add-in is a useful tool designed to enable the user to view what their documents will look like. It is recommended to use the Add-in whilst you are creating your template.
Adding the Build a Doc Word Add-in
To use the Build a Doc Word Add-in for template authoring:
- Open Microsoft Word (Desktop or Online)
- Click the Home tab → Add-ins
- Search for Build a Doc
- Click Add to install
The Build a Doc pane will appear on the right side of Word, ready for template validation and preview.
Providing Sample Data for Preview
Once you’ve created your template structure and added tags, you need to provide sample data to preview the results in the Word Add-in. For detailed guidance on structuring your JSON data, see Structure JSON Data.
Using the Add-in Data Pane
To preview your template with sample data:
- Open the Build a Doc Add-in pane (right side of Word)
- Navigate to the Build tab
- In the data input area, paste your JSON data as an array
- Click Preview to generate a sample document
- Review the generated preview to verify your template tags work correctly
Use array-only format for your preview data. Provide the Invoice data structure from earlier in the guide, wrapped in an array:
[{"Name": "Invoice","Data": {"Customer": {"Name": "John Smith"},"Items": [{"Description": "Product A","Price": 10},{"Description": "Product B","Price": 15.5}]}}]With this data, template tags from the document like <<[Invoice.Customer.Name]>> and <<foreach [item in Invoice.Items]>>...<<[item.Description]>>...<<[item.Price]>><</foreach>> will be populated with the sample values when you click Preview.
- Always use array format at the top level (start with
[and end with]) - Structure object fields inside the array with appropriate nesting
- Include values for all placeholders in your template
- Test arrays with multiple items to ensure loops work correctly
- Include edge cases (empty nested arrays, null values, very long text)
- Test different conditional branches with appropriate data
For comprehensive guidance on preparing and testing sample data, see Preview Templates with Sample Data. For guidance on structuring your JSON data correctly, see Structure JSON Data.
The Authoring Workflow
Creating a template involves three main steps: Structure, Tagging, and Logic.
1. Structure Your Document
Before adding any dynamic tags, build the static layout of your document using standard Word features.
- Tables: Create the headers for your invoices or reports.
- Styles: Apply your headers, formatting, and standard font styles. The generated document will retain all these stylistic choices.
- Placeholders: It is often helpful to type dummy text (e.g., [Client Name]) where you intend to put dynamic data later.
2. Inserting Data Tags
After creating the basic structure of the document, replace your placeholder text with real Build a Doc template syntax that matches your JSON Data structure.
Example JSON Data:
[ { "Name": "Invoice", "Data": { "Customer": { "Name": "John Smith" }, "Items": [ { "Description": "Product A", "Price": 10.0 }, { "Description": "Product B", "Price": 15.5 } ] } }]-
Insert your Basic Fields: To display a simple field, use the path to that data.
- Example: To show the Customer Name, type:
<<[Invoice.Customer.Name]>>
- Example: To show the Customer Name, type:
3. Applying Logic and Formatting
Advanced Expressions
Mathematical Operations
Perform calculations directly in templates:
Subtotal: £<<[Quantity * UnitPrice]>>Tax (20%): £<<[Quantity * UnitPrice * 0.2]>>Total: £<<[Quantity * UnitPrice * 1.2]>>String Operations
Manipulate text values:
<<[CustomerName.ToUpper()]>><<[Description.Substring(0, 50)]>>...Date Formatting
Format dates for display:
<<[OrderDate]:"dd MMMM yyyy">> → 22 January 2025<<[OrderDate]:"dd/MM/yy">> → 22/01/25<<[OrderDate]:"dddd">> → WednesdayVariables
Use variables for running totals and calculations:
Declaring Variables
<<var [grandTotal = 0]>>Updating Variables
Inside loops, accumulate values:
<<foreach [item in Items]>><<var [grandTotal = grandTotal + (item.Quantity * item.Price)]>><<[item.Description]>> - £<<[item.Quantity * item.Price]>><</foreach>>
Grand Total: £<<[grandTotal]>>Complex Conditionals
Multiple Conditions
<<if [Status == "VIP" && TotalPurchases > 1000]>> Premium Customer Discount: 15%<<elseif [TotalPurchases > 500]>> Loyalty Discount: 10%<<else>> Standard Pricing<</if>>Conditional Tables
Show or hide entire table rows:
| Condition | Description |
|---|---|
<<if [ShowShipping]>> | Start conditional row |
| Content here | Row content |
<</if>> | End conditional |
Nested Loops
Handle hierarchical data:
<<foreach [category in Categories]>>Category: <<[category.Name]>>
<<foreach [product in category.Products]>> - <<[product.Name]>>: £<<[product.Price]>><</foreach>>
<</foreach>>Table Techniques
Dynamic Row Expansion
The loop creates one row per item:
| Product | Qty | Price | Total |
|---|---|---|---|
<<foreach [item in Items]>><<[item.Product]>> | <<[item.Qty]>> | £<<[item.Price]>> | £<<[item.Qty * item.Price]>><</foreach>> |
Conditional Rows
Include rows only when conditions are met:
<<if [IncludeDiscount]>>| Discount | | | -£<<[DiscountAmount]>> |<</if>>Summary Rows
Add totals after dynamic content:
| **Total** | | | **£<<[Items.Sum(i => i.Qty * i.Price)]>>** |LINQ Expressions
Use LINQ-style expressions for data manipulation:
Sum
<<[Items.Sum(i => i.Price)]>>Average
<<[Items.Average(i => i.Rating)]>>Count
<<[Items.Count()]>><<[Items.Where(i => i.Status == "Active").Count()]>>Filter
<<foreach [item in Items.Where(i => i.InStock)]>>Order By
<<foreach [item in Items.OrderBy(i => i.Name)]>>Images and Formatting
Preserve Formatting
Template formatting (fonts, colours, styles) is preserved in output.
Dynamic Images
For base64-encoded images:
<<[LogoImage]>>Word Template Operations
| Operation | Examples and Notes |
|---|---|
All(Predicate) | persons.All(p => p.Age < 50) |
Any() | persons.Any() |
Any(Predicate) | persons.Any(p => p.Name == "John Smith") |
Average(Selector) | persons.Average(p => p.Age)The input selector must return a value of any type that has predefined or user-defined addition and division operators. |
Concat(IEnumerable) | persons.Concat(otherPersons)An implicit reference conversion must exist between types of items of concatenated enumerations. |
Contains(Object) | persons.Contains(otherPersons.First()) |
Count() | persons.Count() |
Count(Predicate) | persons.Count(p => p.Age > 30) |
Distinct() | persons.Distinct() |
First() | persons.First() |
First(Predicate) | persons.First(p => p.Age > 30) |
FirstOrDefault() | persons.FirstOrDefault() |
FirstOrDefault(Predicate) | persons.FirstOrDefault(p => p.Age > 30) |
GroupBy(Selector) | persons.GroupBy(p => p.Age)Or: persons.GroupBy(p => new { Age = p.Age, Count = p.Children.Count() })Returns an enumeration of group objects. Each group has a unique Key defined by the selector and can be treated as an enumeration of its items. |
Last() | persons.Last() |
Last(Predicate) | persons.Last(p => p.Age > 100) |
LastOrDefault() | persons.LastOrDefault() |
LastOrDefault(Predicate) | persons.LastOrDefault(p => p.Age > 100) |
Max(ComparableSelector) | persons.Max(p => p.Age) |
Min(ComparableSelector) | persons.Min(p => p.Age) |
OrderBy(ComparableSelector) | persons.OrderBy(p => p.Age)Or: persons.OrderBy(p => p.Age).ThenByDescending(p => p.Name)Or: persons.OrderBy(p => p.Age).ThenByDescending(p => p.Name).ThenBy(p => p.Children.Count())Returns an ordered enumeration. Use ThenBy or ThenByDescending to specify additional keys. |
OrderByDescending(ComparableSelector) | persons.OrderByDescending(p => p.Age)Or: persons.OrderByDescending(p => p.Age).ThenByDescending(p => p.Name)Or: persons.OrderByDescending(p => p.Age).ThenByDescending(p => p.Name).ThenBy(p => p.Children.Count()) |
Select(Selector) | persons.Select(p => p.Name) |
SelectMany(EnumerationSelector) | persons.SelectMany(p => p.Children) |
Single() | persons.Single() |
Single(Predicate) | persons.Single(p => p.Name == "John Smith") |
SingleOrDefault() | persons.SingleOrDefault() |
SingleOrDefault(Predicate) | persons.SingleOrDefault(p => p.Name == "John Smith") |
Skip(int) | persons.Skip(10) |
SkipWhile(Predicate) | persons.SkipWhile(p => p.Age < 21) |
Sum(Selector) | persons.Sum(p => p.Children.Count())The selector must return a value with a predefined or user-defined addition operator. |
Take(int) | persons.Take(5) |
TakeWhile(Predicate) | persons.TakeWhile(p => p.Age < 50) |
Union(IEnumerable) | persons.Union(otherPersons)An implicit reference conversion must exist between types of items of united enumerations. |
Where(Predicate) | persons.Where(p => p.Age > 18) |
Validating Your Template
As you author, frequent validation saves time.
- Use the Preview: The most effective validation is generating a preview.
- Check Error Logs: If generation fails, the Add-in provides an error log. Look for “Unexpected end of tag” (usually a missing
>>) or “Invalid path” (typos in JSON keys).
Best Practices
- Keep logic simple - Complex business logic belongs in your data preparation, not templates
- Test incrementally - Add complexity gradually, testing at each step
- Use meaningful names - Clear variable and data source names improve maintainability
- Document templates - Add comments or maintain separate documentation
- Version control - Track template versions in SharePoint or version control
Publishing Templates to Production
Once validated, store templates in SharePoint Document Libraries or OneDrive for Business with clear versioning.
Recommended Folder Structure
/Templates/├── Production/│ ├── Invoices/Invoice_v1.0.docx│ └── Reports/WeeklySalesDigest_v1.0.xlsx├── Development/└── Archive/Version Management
Use TemplateName_vX.Y.docx naming:
- X = Major version (breaking changes)
- Y = Minor version (bug fixes)
Never modify templates in place - always create new versions. Keep old versions in Archive for rollback.
Deployment Checklist
Before deploying to production:
- Test with representative data including edge cases
- Verify data source keys match template expressions (case-sensitive)
- Confirm service account has read access to template file
- Update flow to reference new template location
- Monitor initial runs and have rollback plan ready