OpenXmlTemplates
Word .docx templating system that is designer (no scripting tags) and server-friendly (no word installation required)
Install / Use
/learn @antonmihaylov/OpenXmlTemplatesREADME
Table of Contents
<!-- ABOUT THE PROJECT -->About The Project
<div align="center"> <img src="/ReadmeImages/screenshot_varaible_before.png?raw=true" width="60%"</img> </div>With the library you can easily:
- Create word templates using only content controls and their tags
- Replace the content controls in a template with actual data from any source (json and a dictionary are natively supported)
- Repeat text based on a list (with nested variables and lists)
- Conditionally remove text section
- Specify a singular and a plural word that should be used conditionally, based of the length of a list
It is server-friendly, because it doesn't require Word installed. Only the Open XML Sdk is used for manipulating the document.
It is friendly to the designer of the document templates, because they don't need to have any coding skills and they won't have to write any script-like snippets in the word document. Everything is instead managed by native Word content controls.
Built With
<!-- GETTING STARTED -->Getting Started
To get a local copy up and running use one of the following methods:
Install via nuget:
nuget install OpenXMLTemplates
or clone the repo and reference OpenXMLTemplates.csproj in your project
git clone https://github.com/antonmihaylov/OpenXmlTemplates.git
<!-- USAGE EXAMPLES -->
Usage
To create a template:
- Open your document in Word
- Open the Developer tab in the ribbon (if you don't have it - open File tab, go to Options > Customize Ribbon. Under Customize the Ribbon and under Main Tabs, select the Developer check box.)
- Under the Controls tab - add a new Content Control of your liking (Plain text is the simplest one - just text with formatting)
- Select the newly added Content control and click Properties in the Developer ribbon
- Change the Tag in the popup window to match one of the supported tags (the tag name is case-insensitive - variable is the same as VARIABLE)
To create a document from a template, using the default content control replacers:
- Create a new TemplateDocument. This represents your document and it neatly handles all
content controls in it, as well as the open/save/close file logic. Don't forget to call Dispose() on it
after you're done, or just use an "using" statement:
using var doc = new TemplateDocument("path/to/my/document.docx"); - Create a new VariableSource (currently available sources are a json string and a dictionary.
You can also create your own class that implements IVariableSource). The variable source handles
your data and extracts it in a way that the template engine can read it.
var src = new VariableSource(jsonString); - Create an OpenXmlTemplateEngine. A default one is provided (DefaultOpenXmlTemplateEngine).
The default one contains all control replacers listed in the readme. You can disable/enable a control replacer by
modifying the IsEnabled variable in it. You can also register your own replacer by calling RegisterReplacer on the engine.
var engine = new DefaultOpenXmlTemplateEngine(); - Call the ReplaceAll method on the engine using the document and the variable source
engine.ReplaceAll(doc, src); - Save the edited document
doc.SaveAs("result.docx");
If you want to remove the content controls from the final document, but keep the content you have two options:
- Use the RemoveControlsAndKeepContent method on the TemplateDocument object or
- Set the KeepContentControlAfterReplacement boolean of the OpenXmlTemplateEngine
Supported Tags
Note that if your variable names contain an underscore results may be unpredictable! Note: to insert a new line, add a new line character (\r\n, \n\r, \n) in the data you provide, it will be parsed as a line break
Variable
-
Tag name: "variable_<NAME OF YOUR VARIABLE>" (the variable keyword is case-insensitive)
-
Replaces the text inside the control with the value of the variable with the provided name
-
Supports nested variable names (e.g. address.street)
-
Supports array access (e.g. names.[0])
-
Supports nested variables using rich text content controls. For example: a rich text content control with tag name address, followed by an inner content control with tag name variable_street is the same as variable.street
-
Note that if you reference a variable from a nested control, that is available in the outer scope, but not in the inner scope - the outer scope variable will be used.
-
Supports variables inside repeating items, the variable name is relative to the repeated item.
Example:
- See example files in the OpenXmlTemplatesTest/ControlReplacerTests/VariableControlReplacerTests folder and in the OpenXmltemplatesTest/EngineTest folder

Repeating
-
Tag name: "repeating_<NAME OF YOUR VARIABLE>" (the repeating keyword is case-insensitive)
-
Repeats the content control as many times as there are items in the variable identified by the provided variable name.
-
Complex fields with inner content controls are supported. Use the inner controls as you would normally, except that the variable names will be relative to the list item. All default content controls can be nested.
-
Note that if you reference a variable from a nested control, that is available in the outer scope, but not in the inner scope (the list item) - the outer scope variable will be used. That is useful if you want to include something in your list item's text output that is available in the global scope only.
-
Add an inner content control with tag variable_index to insert the index of the current item (1-based)
-
You can add extra arguments to the tag name (e.g. "repeating_<VARIABLE NAME>_extraparam1_extraparam2..."):
- "separator_<INSERT SEPARATOR STRING>"- inserts a separator after each item (e.g. "repeating_<VARIABLE NAME>separator, " - this inserts a comma between each item)
- "lastSeparator_<INSERT SEPARATOR STRING>"- inserts a special sepeartor before the last item (e.g. "repeating_<VARIABLE NAME>separator, _lastSeparator_and " - this inserts a comma between each item and an "and" before the last item)
Example:
- See example files in the OpenXmlTemplatesTest/ControlReplacerTests/RepeatingControlTests folder and in the OpenXmltemplatesTest/EngineTest folder

Conditional remove
-
Tag name: "conditionalRemove_<ENTER THE NAME OF YOUR VARIABLE>" (the conditionalRemove keyword is case-insensitive)
-
Removes content controls based on the value of the provided variable
-
If the variable value is evaluated to true (True, "true", 1, "1", non-empty list, non-empty dict) the control stays. If it doesn't - it is removed
-
You can add extra arguments to the tag name (e.g. "conditionalRemove_<VARIABLE NAME>_extraparam1_extraparam2..."):
- "OR" - applies an OR operation to the values. The control is removed if none of the values between the operator are true. (e.g. "conditionalRemove_<VARIABLE NAME 1>or<VARIABLE NAME 2>")
- "EQ", "GT" and "LT" - checks if the value of the first variable equals ("eq"), is greather than ("gt") or is less than ("lt") the second variable's value. (e.g. "conditionalRemove_<VARIABLE NAME 1>lt<VARIABLE NAME 2>"). You can also provide a value to the operation, instead of a variable name (e.g. "conditionalRemove_<VARIABLE NAME>_lt_2). The control is removed if the supplied condition evaluates to false.
- "NOT" - reverses the last value. (e.g. "conditionalRemove_<VARIABLE NAME>_not)
-
You can also chain multiple arguments, e.g. "conditionalRemove_<VARIABLE NAME 1>not_or_<VARIABLE NAME 2>and<VARIABLE NAME 3>". Note that the expression is evaluated from left to right, with no recognition for the order of operations.
Example:
- See example files in the [OpenXmlTemplatesTest/ControlReplacerTests/ConditionalControlReplacerTest
Related Skills
clearshot
Structured screenshot analysis for UI implementation and critique. Analyzes every UI screenshot with a 5×5 spatial grid, full element inventory, and design system extraction — facts and taste together, every time. Escalates to full implementation blueprint when building. Trigger on any digital interface image file (png, jpg, gif, webp — websites, apps, dashboards, mockups, wireframes) or commands like 'analyse this screenshot,' 'rebuild this,' 'match this design,' 'clone this.' Skip for non-UI images (photos, memes, charts) unless the user explicitly wants to build a UI from them. Does NOT trigger on HTML source code, CSS, SVGs, or any code pasted as text.
openpencil
2.0kThe world's first open-source AI-native vector design tool and the first to feature concurrent Agent Teams. Design-as-Code. Turn prompts into UI directly on the live canvas. A modern alternative to Pencil.
HappyColorBlend
HappyColorBlendVibe Project Guidelines Project Overview HappyColorBlendVibe is a Figma plugin for color palette generation with advanced tint/shade blending capabilities. It allows designers to
Flyaro-waffle-app
Waffle Delight - Full Stack MERN Application Rules & Documentation Project Overview A comprehensive waffle delivery application built with MERN stack featuring premium UI/UX, admin management, a
