-
Notifications
You must be signed in to change notification settings - Fork 0
Template Syntax
FlexRender templates are YAML files that define image layouts using a tree of typed elements. This page covers the template structure, all 11 element types, common properties, and supported units.
For template expressions (variables, loops, conditionals), see Template-Expressions. For flexbox layout properties, see Flexbox-Layout. For a complete property reference with examples for every element type, see Element-Reference. For visual examples with rendered images, see Visual-Reference.
template: # Required: metadata
name: "my-template" # Template name (string)
version: 1 # Template version (int)
culture: "ru-RU" # Culture for number/date formatting (optional)
fonts: # Optional: font definitions (list or dictionary)
- "assets/fonts/Inter-Regular.ttf" # First unnamed = "default"/"main"
- "assets/fonts/Inter-Bold.ttf"
canvas: # Required: canvas configuration
fixed: width # Which dimension is fixed
width: 300 # Canvas width in pixels
background: "#ffffff" # Background color
text-direction: ltr # Text direction: ltr (default), rtl
layout: # Required: array of elements
- type: text
content: "Hello!"| Property | Type | Default | Description |
|---|---|---|---|
name |
string | "" |
Template name for identification |
version |
int | 1 |
Template version number |
culture |
string? | null |
Culture for number/date formatting (e.g., "ru-RU", "en-US"). When set, built-in filters use this culture instead of InvariantCulture. Priority: RenderOptions.Culture > template.culture > InvariantCulture |
| Property | Type | Default | Description |
|---|---|---|---|
fixed |
FixedDimension | width |
Which dimension is fixed: width, height, both, none
|
width |
int | 300 |
Canvas width in pixels |
height |
int | 0 |
Canvas height (0 = auto when not fixed) |
background |
string | "#ffffff" |
Background color in hex |
rotate |
string | "none" |
Post-render rotation |
text-direction |
TextDirection | ltr |
Text direction: ltr, rtl
|
-
width-- width is fixed, height expands to fit content (default) -
height-- height is fixed, width expands to fit content -
both-- both dimensions are fixed -
none-- both dimensions expand to fit content
| Value | Effect |
|---|---|
"none" |
No rotation |
"left" |
270 degrees (90 CCW) -- swaps width/height |
"right" |
90 degrees CW -- swaps width/height |
"flip" |
180 degrees |
"<number>" |
Arbitrary degrees (e.g., "45") |
Rotation is applied after rendering. For thermal printers: use "right" to rotate a wide receipt into a tall image.
FlexRender supports two formats for font registration: dictionary format (legacy) and list format (recommended). Supported file types: .ttf and .otf. Font sources can be local file paths, embedded:// resources, or http:// URLs.
Key-value pairs where the key is a reference name used in font: properties:
fonts:
default: "assets/fonts/Inter-Regular.ttf"
heading: "assets/fonts/Roboto-Regular.ttf"
icon: "embedded://MyApp.Fonts.icons.ttf"
remote: "https://example.com/font.ttf"An array of font entries. Simple strings and objects with path/name/fallback can be mixed freely:
fonts:
# Simple strings -- first unnamed font automatically becomes "default" (and "main")
- "assets/fonts/Inter-Regular.ttf"
- "assets/fonts/Inter-Bold.ttf"
- "assets/fonts/Inter-Italic.ttf"
# With optional name and fallback
- path: "assets/fonts/Roboto-Regular.ttf"
name: heading
fallback: "Arial"Rules:
- The first unnamed font automatically becomes
default(andmain) - Fonts can be mixed: simple strings and objects with
path/name/fallback - Named fonts are referenced via
font:on elements (e.g.,font: heading)
| Property | Type | Default | Description |
|---|---|---|---|
font |
string | main |
Reference to a registered font name |
fontFamily |
string | (empty) | CSS-like font family name -- searches registered fonts by FamilyName, then system fonts |
fontWeight |
string/number | normal |
Font weight: thin(100), extra-light(200), light(300), normal(400), medium(500), semi-bold(600), bold(700), extra-bold(800), black(900), or numeric |
fontStyle |
string | normal |
Font style: normal, italic, oblique
|
font (registered name) > fontFamily (family name) > fallback (default)
- If
fontis set to a non-default value, resolve by registered name - If
fontFamilyis set, search registered fonts by FamilyName metadata, then system fonts - Otherwise, use the default font (
main)
For weight/style variants: automatic sibling discovery scans the same directory as the base font file for .ttf/.otf files with matching family name and weight/style.
You only need to register the regular/default font for each family. When fontWeight or fontStyle is used on a text element, FlexRender automatically scans the same directory for font files with a matching family name and weight/style (within +/-100 units for weight, case-insensitive).
Convention: Place all weight/style variants of a font family in the same directory:
assets/fonts/
Inter-Regular.ttf # weight 400, upright
Inter-Bold.ttf # weight 700, upright
Inter-SemiBold.ttf # weight 600, upright
Inter-Italic.ttf # weight 400, italic
Inter-BoldItalic.ttf # weight 700, italic
Then fontWeight: bold on a text element will automatically use Inter-Bold.ttf without any extra font registration.
Tables support font properties on the header row:
| Property | Aliases | Description |
|---|---|---|
headerFont |
header-font |
Font name for header cells |
headerFontWeight |
header-fontWeight |
Font weight for headers |
headerFontStyle |
header-fontStyle |
Font style for headers (normal, italic, oblique) |
headerFontFamily |
header-fontFamily |
CSS-like font family for headers |
| Value | Numeric |
|---|---|
thin |
100 |
extra-light |
200 |
light |
300 |
normal (default) |
400 |
medium |
500 |
semi-bold |
600 |
bold |
700 |
extra-bold |
800 |
black |
900 |
Numeric values (100-900) are also accepted directly: fontWeight: 600.
normal (default), italic, oblique.
Minimal (system fonts only, no registration):
layout:
- type: text
content: "Hello"
fontFamily: "Arial"
fontWeight: boldList registration with fontWeight/fontStyle:
fonts:
- "assets/fonts/Inter-Regular.ttf"
- "assets/fonts/Inter-Bold.ttf"
- "assets/fonts/Inter-Italic.ttf"
layout:
- type: text
content: "Bold text"
fontWeight: bold
- type: text
content: "Italic text"
fontStyle: italicMixed: named + unnamed, font + fontFamily:
fonts:
- "assets/fonts/Inter-Regular.ttf"
- path: "assets/fonts/NotoSansArabic-Regular.ttf"
name: arabic
layout:
- type: text
content: "Inter bold"
fontWeight: bold
- type: text
content: "System Georgia"
fontFamily: "Georgia"
- type: text
content: "Arabic"
font: arabic- Variable fonts are NOT supported -- SkiaSharp 3.x does not expose an API for font variation axes. Use separate static font files per weight/style instead.
- Sibling discovery relies on font file metadata (family name, weight, slant). If files use non-standard naming, register them explicitly.
Colors are specified in hex format:
-
#rrggbb-- 6-digit hex (e.g.,"#ff0000"for red) -
#rgb-- 3-digit hex shorthand (e.g.,"#f00"for red)
Renders text content with font, size, color, alignment, and wrapping options.
- type: text
content: "Hello, {{name}}!"
font: bold
size: 1.2em
color: "#000000"
align: center
wrap: true
overflow: ellipsis
maxLines: 2
lineHeight: "1.5"| Property | Type | Default | Description |
|---|---|---|---|
content |
string | "" |
Text content, may contain {{variable}} expressions |
font |
string | "main" |
Font reference name from fonts section |
fontFamily |
string | "" |
CSS-like font family name -- searches registered fonts by FamilyName, then system fonts |
size |
string | "1em" |
Font size (px, em, %) |
color |
string | "#000000" |
Text color in hex |
align |
TextAlign | left |
Text alignment: left, center, right, start (logical), end (logical) |
wrap |
bool | true |
Whether text wraps to multiple lines |
overflow |
TextOverflow | ellipsis |
Overflow handling: ellipsis, clip, visible
|
maxLines |
int? | null |
Maximum number of lines (null = unlimited) |
lineHeight |
string | "" |
Line height for multi-line text |
fontWeight |
FontWeight | normal |
Font weight: thin, extra-light, light, normal, medium, semi-bold, bold, extra-bold, black, or numeric 100-900 |
fontStyle |
FontStyle | normal |
Font style: normal, italic, oblique
|
lineHeight values:
| Format | Example | Behavior |
|---|---|---|
| Empty string | "" |
Use font-defined default spacing |
| Plain number | "1.8" |
Multiplier of fontSize |
| Pixel units | "24px" |
Absolute pixel value |
| Em units | "2em" |
Relative to element's fontSize |
A container that lays out children using the flexbox algorithm. See Flexbox-Layout for detailed layout properties.
- type: flex
direction: row
wrap: wrap
gap: 10
justify: space-between
align: center
padding: "20"
background: "#f5f5f5"
children:
- type: text
content: "Left"
- type: text
content: "Right"| Property | Type | Default | Description |
|---|---|---|---|
direction |
FlexDirection | column |
Main axis: row, column, row-reverse, column-reverse
|
wrap |
FlexWrap | nowrap |
Wrapping: nowrap, wrap, wrap-reverse
|
gap |
string | "0" |
Gap shorthand (sets both rowGap and columnGap) |
columnGap |
string? | null |
Gap between items along the main axis |
rowGap |
string? | null |
Gap between wrapped lines |
justify |
JustifyContent | start |
Main axis alignment |
align |
AlignItems | stretch |
Cross axis alignment |
alignContent |
AlignContent | start |
Wrapped lines alignment |
overflow |
Overflow | visible |
Content clipping: visible, hidden
|
children |
element[] | [] |
Child elements |
Renders an image from a file, URL, base64 data, or embedded resource.
# From file
- type: image
src: "logo.png"
width: 100
height: 50
# From HTTP
- type: image
src: "https://example.com/logo.png"
# From embedded resource
- type: image
src: "embedded://MyApp.Resources.logo.png"
# From base64
- type: image
src: "data:image/png;base64,iVBOR..."| Property | Type | Default | Description |
|---|---|---|---|
src |
string | "" |
Image source: relative file path, file: URI, http://, embedded://, or base64 data URL. Only relative paths are allowed (absolute paths rejected for security). |
width |
int? | null |
Image container width (null = natural width) |
height |
int? | null |
Image container height (null = natural height) |
fit |
ImageFit | contain |
How the image fits within bounds |
Image fit modes:
| Mode | Description |
|---|---|
fill |
Stretch to fill bounds (may distort) |
contain |
Scale to fit within bounds preserving ratio (may have empty space) |
cover |
Scale to cover bounds preserving ratio (may be cropped) |
none |
Use image's natural size without scaling |
Renders a QR code. Requires FlexRender.QrCode.Skia.Render (or FlexRender.QrCode) and .WithQr() on the builder for Skia, or FlexRender.QrCode.ImageSharp.Render for ImageSharp.
- type: qr
data: "{{paymentUrl}}"
size: 120
errorCorrection: M
foreground: "#000000"| Property | Type | Default | Description |
|---|---|---|---|
data |
string | "" |
Data to encode in the QR code |
size |
int | 100 |
QR code size in pixels (width = height) |
errorCorrection |
ErrorCorrectionLevel | M |
Error correction level |
foreground |
string | "#000000" |
Foreground (module) color in hex |
Error correction levels:
| Level | Recovery Capacity |
|---|---|
L |
~7% recovery |
M |
~15% recovery (default) |
Q |
~25% recovery |
H |
~30% recovery |
Renders a barcode. Requires FlexRender.Barcode.Skia.Render (or FlexRender.Barcode) and .WithBarcode() on the builder for Skia, or FlexRender.Barcode.ImageSharp.Render for ImageSharp.
- type: barcode
data: "{{sku}}"
format: code128
width: 200
height: 80
showText: true
foreground: "#000000"| Property | Type | Default | Description |
|---|---|---|---|
data |
string | "" |
Data to encode |
format |
BarcodeFormat | code128 |
Barcode format |
width |
int | 200 |
Barcode width in pixels |
height |
int | 80 |
Barcode height in pixels |
showText |
bool | true |
Show encoded text below barcode |
foreground |
string | "#000000" |
Bar color in hex |
Barcode formats:
| Format | Description |
|---|---|
code128 |
Alphanumeric, high density |
code39 |
Alphanumeric, widely supported |
ean13 |
13 digits, retail |
ean8 |
8 digits, compact retail |
upc |
12 digits, North American retail (UPC-A) |
Renders a horizontal or vertical line (solid, dashed, or dotted).
- type: separator
style: dashed
color: "#cccccc"
thickness: 1| Property | Type | Default | Description |
|---|---|---|---|
orientation |
SeparatorOrientation | horizontal |
Direction: horizontal, vertical
|
style |
SeparatorStyle | dotted |
Line style: dotted, dashed, solid
|
thickness |
float | 1 |
Line thickness in pixels |
color |
string | "#000000" |
Line color in hex |
Horizontal separators stretch to full width and use thickness as height. Vertical separators stretch to full height and use thickness as width.
Renders tabular data with configurable columns, optional headers, and support for both dynamic (data-driven) and static rows. The table element is expanded into a flex-based layout during template expansion -- no changes to the layout or rendering engines are needed.
# Dynamic table from data array
- type: table
array: items
as: item
columns:
- key: name
label: "Product"
grow: 1
- key: price
label: "Price"
width: "80"
align: right| Property | Type | Default | Description |
|---|---|---|---|
array |
string | "" |
Path to data array for dynamic rows |
as |
string? | null |
Variable name for current item |
columns |
column[] | required | Column definitions |
rows |
row[] | [] |
Static rows (alternative to array) |
headerFont |
string? | null |
Font for header row |
headerFontWeight |
string? | null |
Font weight for header row |
headerFontStyle |
string? | null |
Font style for header row (normal, italic, oblique) |
headerFontFamily |
string? | null |
CSS-like font family for header row |
headerColor |
string? | null |
Text color for header row |
headerSize |
string? | null |
Font size for header row |
headerBackground |
string? | null |
Background color for header row |
Column properties:
| Property | Type | Default | Description |
|---|---|---|---|
key |
string | required | Data field name for this column |
label |
string? | null |
Header text (null = no header for this column) |
width |
string? | null |
Explicit column width (px, %, em) |
grow |
float | 0 |
Flex grow factor |
align |
TextAlign | left |
Text alignment: left, center, right
|
font |
string? | null |
Font override for cells in this column |
color |
string? | null |
Text color override |
size |
string? | null |
Font size override |
format |
string? | null |
Format string for cell values |
Static row properties:
| Property | Type | Default | Description |
|---|---|---|---|
values |
map | required | Column key to value mapping |
font |
string? | null |
Font override for this row |
color |
string? | null |
Text color override |
size |
string? | null |
Font size override |
Embeds dynamically formatted text (Markdown, HTML, NDC, etc.) from template data using pluggable content parsers. Like each and if, this is a control-flow element expanded at render time.
- type: content
source: "{{body}}"
format: markdown| Property | Type | Default | Description |
|---|---|---|---|
source |
string | "" |
The formatted text to parse. Usually bound to a {{variable}}. |
format |
string | "" |
Content format: markdown, html, ndc, or any registered parser name. |
options |
dict? | null |
Parser-specific options dictionary (used by NDC and custom parsers). |
See Element-Reference#content-element-control-flow for full details, element mapping, and examples.
Iterates over an array in the data, creating child elements for each item. See Template-Expressions for details.
- type: each
array: items
as: item
children:
- type: text
content: "{{@index}}. {{item.name}}: {{item.price}}"| Property | Type | Required | Description |
|---|---|---|---|
array |
string | Yes | Path to array in data (e.g., "items", "order.lines") |
as |
string | No | Variable name for current item |
children |
element[] | Yes | Template elements to render per item |
Conditional rendering based on data values. Supports 13 comparison operators. See Template-Expressions for details.
- type: if
condition: isPremium
then:
- type: text
content: "Premium member"
else:
- type: text
content: "Standard member"| Property | Type | Required | Description |
|---|---|---|---|
condition |
string | Yes | Path to value for condition check |
then |
element[] | Yes | Elements when condition is true |
elseIf |
if element | No | Nested else-if condition |
else |
element[] | No | Elements when all conditions are false |
Renders SVG vector graphics in templates. Supports external files (src) or inline markup (content).
Requires
FlexRender.SvgElement.Skia.Render(orFlexRender.SvgElement) package:.WithSkia(skia => skia.WithSvgElement())
# From file
- type: svg
src: "assets/icons/logo.svg"
width: 120
height: 40
# Inline SVG
- type: svg
content: '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="#4CAF50"/></svg>'
width: 48
height: 48| Property | Type | Default | Description |
|---|---|---|---|
src |
string? | null |
Path to SVG file. Loaded via resource loaders (file, HTTP, embedded). Mutually exclusive with content. |
content |
string? | null |
Inline SVG markup string. Mutually exclusive with src. |
width |
int? | null |
Target render width in pixels. null = use SVG intrinsic width or container. |
height |
int? | null |
Target render height in pixels. null = use SVG intrinsic height or container. |
fit |
ImageFit | contain |
How the SVG fits within its bounds: fill, contain, cover, none. |
Must specify exactly one of src or content (not both, not neither).
All elements inherit these properties from TemplateElement:
| Property | Type | Default | Description |
|---|---|---|---|
padding |
string | "0" |
Inner spacing (px, %, em, CSS shorthand) |
margin |
string | "0" |
Outer spacing (px, %, em, auto, CSS shorthand) |
background |
string? | null |
Background color in hex or gradient (null = transparent) |
opacity |
float | 1.0 |
Element opacity from 0.0 (fully transparent) to 1.0 (fully opaque) |
box-shadow |
string? | null |
Box shadow: "offsetX offsetY blurRadius color" (e.g., "4 4 8 #00000040") |
rotate |
string | "none" |
Element rotation (none/left/right/flip/degrees) |
display |
Display | flex |
Display mode: flex, none
|
grow |
float | 0 |
Flex grow factor |
shrink |
float | 1 |
Flex shrink factor |
basis |
string | "auto" |
Flex basis (px, %, em, auto) |
alignSelf |
AlignSelf | auto |
Per-item alignment override |
order |
int | 0 |
Display order |
width |
string? | null |
Explicit width (px, %, em, auto) |
height |
string? | null |
Explicit height (px, %, em, auto) |
minWidth |
string? | null |
Minimum width constraint |
maxWidth |
string? | null |
Maximum width constraint |
minHeight |
string? | null |
Minimum height constraint |
maxHeight |
string? | null |
Maximum height constraint |
position |
Position | static |
Positioning mode: static, relative, absolute
|
top |
string? | null |
Top inset for positioned elements |
right |
string? | null |
Right inset for positioned elements |
bottom |
string? | null |
Bottom inset for positioned elements |
left |
string? | null |
Left inset for positioned elements |
aspectRatio |
float? | null |
Width/height ratio constraint |
text-direction |
TextDirection? | null |
Text direction override: ltr, rtl (null = inherit from parent/canvas) |
All size-based properties support the following units:
| Unit | Syntax | Description | Example |
|---|---|---|---|
| px |
"100", "100px"
|
Absolute pixels (default if no suffix) | width: "100" |
| % | "50%" |
Percentage of parent container size | width: "50%" |
| em | "1.5em" |
Relative to current font size | size: "1.5em" |
| auto |
"auto", null
|
Automatic sizing (context-dependent) | width: "auto" |
Plain numbers without suffix are treated as pixels. Empty or whitespace strings resolve to auto. Parsing is case-insensitive for unit suffixes.
Both padding and margin accept 1 to 4 space-separated values:
| Format | Meaning |
|---|---|
"20" |
All sides = 20 |
"20 40" |
Top/Bottom = 20, Left/Right = 40 |
"20 40 30" |
Top = 20, Left/Right = 40, Bottom = 30 |
"20 40 30 10" |
Top = 20, Right = 40, Bottom = 30, Left = 10 |
Each value can use a different unit: "10px 5% 2em 20".
Margin additionally supports auto values for centering elements within flex containers. See Flexbox-Layout for auto margin details.
A receipt template demonstrating multiple element types:
template:
name: "receipt"
version: 1
fonts:
default: "assets/fonts/Inter-Regular.ttf"
bold: "assets/fonts/Inter-Bold.ttf"
canvas:
fixed: width
width: 320
background: "#ffffff"
layout:
- type: flex
padding: "24 20"
gap: 12
children:
# Header
- type: text
content: "{{shopName}}"
font: bold
size: 1.5em
align: center
color: "#1a1a1a"
- type: separator
style: dashed
color: "#cccccc"
# Items (dynamic loop)
- type: each
array: items
as: item
children:
- type: flex
direction: row
justify: space-between
children:
- type: text
content: "{{item.name}}"
color: "#333333"
- type: text
content: "{{item.price}} $"
color: "#333333"
- type: separator
style: solid
color: "#1a1a1a"
# Total
- type: flex
direction: row
justify: space-between
children:
- type: text
content: "TOTAL"
font: bold
size: 1.2em
- type: text
content: "{{total}} $"
font: bold
size: 1.2em
# QR code
- type: flex
align: center
children:
- type: qr
data: "{{paymentUrl}}"
size: 120
errorCorrection: M
- type: text
content: "Thank you for your purchase!"
size: 0.85em
align: center
color: "#666666"- Element-Reference -- complete property reference for all element types
- Template-Expressions -- variables, loops, conditionals
- Flexbox-Layout -- layout engine details
- Render-Options -- rendering and format options