HTML tag reference
This is the supported letter HTML vocabulary. Every tag below has a placement rule and example. The reference build compares this catalogue against the implementation’s region/block/inline/layout vocabulary, preventing unnoticed additions/removals.
Parsing rules
Section titled “Parsing rules”Use a single letter root with a required main body. Do not add browser html, head or body wrappers. Unsupported tags, attributes, styles and HTML recovery fail with a source location. Comments and structural indentation are allowed; explicit text belongs in appropriate text blocks.
Use paired closing tags for custom empty elements: page-break, component, page-number and page-count. Standard img, br and param are void tags. Escape literal markup as </&; template values are literal text and cannot create markup.
Common attributes and exceptions
Section titled “Common attributes and exceptions”style selects supported inline CSS. style-name names a document-local theme style. They are allowed only where the tag supports styling: logo has no wrapper appearance; watermark forbids named styles and has special appearance rules; if, else, param and page-break have stricter attribute restrictions.
data-if selects an element using a Boolean map path. data-each repeats supported blocks/rows using a List path, with required data-as alias. These attributes are processed only in template mode, before normal tag validation. They are not arbitrary expressions; see the directive reference.
Tag index
Section titled “Tag index”<letter>
- Placement
- Exactly one root
- Defaults
- A4 portrait; 20 mm margins; 25 mm header; 15 mm footer; en-GB, LONG dates, UTC; no selected currency.
Use letter markup without html/head/body wrappers. Root typography is inherited by content; use Java for independent per-side margins. Custom paper dimensions are a pair. Positive-size paper must accommodate margins/zones.
| Attribute | Accepted input / meaning |
|---|---|
page | a4 or letter; case-insensitive |
orientation | portrait or landscape |
page-width-mm | Positive custom paper width; requires page-height-mm |
page-height-mm | Positive custom paper height; requires page-width-mm |
margins-mm | Finite uniform physical page margin, in mm |
header-height-mm | Reserved header height in mm |
footer-height-mm | Reserved footer height in mm |
language-tag | BCP 47 language/country identifier |
date-pattern | Java DateTimeFormatter pattern |
date-style | FULL, LONG, MEDIUM or SHORT |
currency | ISO 4217 currency code |
zone-id | Java ZoneId name; affects temporal formatting |
<letter page="a4" margins-mm="20"><main><p>Hello</p></main></letter><main>
- Placement
- Required direct child of letter
- Defaults
- One required region; body blocks keep source order.
Only the body flow permits explicit page-break blocks. A selected template must contain renderable body content.
<main><p>Body text</p></main><header>
- Placement
- Direct child of letter; unique per page selector
- Defaults
- All pages; automatic left-aligned placement; height derives from header-height-mm.
Exact placement requires x-mm, y-mm, width-mm and height-mm together. Text alignment can be overridden on child blocks. Put paragraph margins on child p/div blocks. FIRST/FOLLOWING variants override ALL on matching pages.
| Attribute | Accepted input / meaning |
|---|---|
pages | all, first or following |
align | left, center or right; controls box placement and initial text alignment |
width-mm | Positive header width in mm |
height-mm | Positive header height in mm |
x-mm | Exact x relative to inner page; requires all four bounds |
y-mm | Exact y relative to inner page; requires all four bounds |
<header pages="first" align="right"><p>Company address</p></header><footer>
- Placement
- Direct child of letter; unique per page selector
- Defaults
- All pages; fitting height uses footer-height-mm.
Supported rich blocks and images; no page breaks. Reserve sufficient height on letter. Put text spacing on child blocks.
| Attribute | Accepted input / meaning |
|---|---|
pages | all, first or following |
<footer pages="all"><p>Page <page-number></page-number> of <page-count></page-count></p></footer><logo>
- Placement
- Direct child of letter
- Defaults
- Image fitting box 45 × 20 mm.
Exactly one img child. Apply dimensions/styles to img, not to the logo wrapper. Named image assets only.
<logo><img src="asset:logo" width="40mm" alt="Example Company"></logo><signature>
- Placement
- Direct child of letter
- Defaults
- flow; 20 mm.
Styled text/images/blocks; no page breaks. bottom-last places the signature on the final generated letter page above the footer. This is a visible signature, not cryptographic signing.
| Attribute | Accepted input / meaning |
|---|---|
placement | flow or bottom-last (bottom_last also accepted) |
height-mm | Finite positive signature reservation, in mm |
<signature placement="bottom-last" height-mm="20"><p>Customer Services</p></signature><watermark>
- Placement
- Direct child of letter
- Defaults
- All pages; opacity 0.12; text 45° / image 0°; image fitting box 80 × 40 mm.
Either plain text or exactly one img child. Text uses independent watermark font/color/size defaults and permits only regular undecorated text. No named style. Image styles belong on img. Standard PDF profile only; does not reserve body space.
| Attribute | Accepted input / meaning |
|---|---|
opacity | Finite number from 0 through 1 |
rotation | Finite rotation in degrees, about page center |
pages | all, first or following |
<watermark opacity="0.12" rotation="45">DEMONSTRATION</watermark><sender>
- Placement
- Direct child of letter
- Defaults
- Optional semantic regions; role defaults/theme apply.
Rich block content. Fluent/HTML semantic parts assemble in conventional letter order rather than arbitrary root tag order. Each role is unique.
<sender><p>Example content</p></sender><recipient>
- Placement
- Direct child of letter
- Defaults
- Optional semantic regions; role defaults/theme apply.
Rich block content. Fluent/HTML semantic parts assemble in conventional letter order rather than arbitrary root tag order. Each role is unique.
<recipient><p>Example content</p></recipient><subject>
- Placement
- Direct child of letter
- Defaults
- Optional semantic regions; role defaults/theme apply.
Rich block content. Fluent/HTML semantic parts assemble in conventional letter order rather than arbitrary root tag order. Each role is unique.
<subject><p>Example content</p></subject><salutation>
- Placement
- Direct child of letter
- Defaults
- Optional semantic regions; role defaults/theme apply.
Rich block content. Fluent/HTML semantic parts assemble in conventional letter order rather than arbitrary root tag order. Each role is unique.
<salutation><p>Example content</p></salutation><closing>
- Placement
- Direct child of letter
- Defaults
- Optional semantic regions; role defaults/theme apply.
Rich block content. Fluent/HTML semantic parts assemble in conventional letter order rather than arbitrary root tag order. Each role is unique.
<closing><p>Example content</p></closing><date>
- Placement
- Direct child of letter
- Defaults
- Final document locale/date pattern formats a value attribute.
Choose value with no child content, or authored rich date content without value. Supports semantic DATE theme styling.
| Attribute | Accepted input / meaning |
|---|---|
value | ISO LocalDate, such as 2026-10-20 |
<date value="2026-10-20"></date><reference>
- Placement
- Direct child of letter
- Defaults
- Semantic REFERENCE role.
Authored rich content follows the configured label.
| Attribute | Accepted input / meaning |
|---|---|
label | Required nonblank reference label |
<reference label="Account"><p>DEMO-000001</p></reference><p>
- Placement
- Inside a region, rich cell, group or supported container
- Defaults
- Inherited body typography; ordinary paragraph flow.
Inline text and formatting. Source whitespace is normalized by markup parsing; use br for explicit lines. Images are separate blocks.
<p>Hello <strong>${name}</strong>.<br>Second line.</p><h1>
- Placement
- Block content inside supported regions/containers
- Defaults
- Bold; semantic sizes h1=18, h2=16, h3=14, h4=12, h5=11, h6=10 pt, below named/explicit overrides; keep with next.
Inline formatted heading text. Current tagged-PDF model emits H1 for every heading level; HTML level does not establish a complete PDF heading hierarchy.
<h1>Account update</h1><h2>
- Placement
- Block content inside supported regions/containers
- Defaults
- Bold; semantic sizes h1=18, h2=16, h3=14, h4=12, h5=11, h6=10 pt, below named/explicit overrides; keep with next.
Inline formatted heading text. Current tagged-PDF model emits H1 for every heading level; HTML level does not establish a complete PDF heading hierarchy.
<h2>Account update</h2><h3>
- Placement
- Block content inside supported regions/containers
- Defaults
- Bold; semantic sizes h1=18, h2=16, h3=14, h4=12, h5=11, h6=10 pt, below named/explicit overrides; keep with next.
Inline formatted heading text. Current tagged-PDF model emits H1 for every heading level; HTML level does not establish a complete PDF heading hierarchy.
<h3>Account update</h3><h4>
- Placement
- Block content inside supported regions/containers
- Defaults
- Bold; semantic sizes h1=18, h2=16, h3=14, h4=12, h5=11, h6=10 pt, below named/explicit overrides; keep with next.
Inline formatted heading text. Current tagged-PDF model emits H1 for every heading level; HTML level does not establish a complete PDF heading hierarchy.
<h4>Account update</h4><h5>
- Placement
- Block content inside supported regions/containers
- Defaults
- Bold; semantic sizes h1=18, h2=16, h3=14, h4=12, h5=11, h6=10 pt, below named/explicit overrides; keep with next.
Inline formatted heading text. Current tagged-PDF model emits H1 for every heading level; HTML level does not establish a complete PDF heading hierarchy.
<h5>Account update</h5><h6>
- Placement
- Block content inside supported regions/containers
- Defaults
- Bold; semantic sizes h1=18, h2=16, h3=14, h4=12, h5=11, h6=10 pt, below named/explicit overrides; keep with next.
Inline formatted heading text. Current tagged-PDF model emits H1 for every heading level; HTML level does not establish a complete PDF heading hierarchy.
<h6>Account update</h6><div>
- Placement
- Block content inside regions/containers
- Defaults
- Text-only div becomes a text block; block children make an inherited style scope.
Style scopes preserve named-style inheritance. Mixing bare text with child block elements is rejected; wrap prose in p when grouping blocks.
<div style="color:#12665B"><p>First paragraph</p><p>Second paragraph</p></div><group>
- Placement
- Block content inside regions/containers
- Defaults
- Soft keep-together by default; style can choose auto/prefer/always.
Groups supported blocks. An impossible strict keep can fail. Page breaks are only allowed where the enclosing body context permits them.
<group style="keep-together:prefer"><h3>Heading</h3><p>Related text.</p></group><span>
- Placement
- Inline text within paragraphs, headings and list/cell text
- Defaults
- span inherits; strong/b set bold; em/i set italic; u sets underline.
Use style/style-name for supported typography. Explicit false/normal values can override inherited emphasis. Styles must name registered or standard font faces.
<p>Normal <span>emphasized text</span>.</p><strong>
- Placement
- Inline text within paragraphs, headings and list/cell text
- Defaults
- span inherits; strong/b set bold; em/i set italic; u sets underline.
Use style/style-name for supported typography. Explicit false/normal values can override inherited emphasis. Styles must name registered or standard font faces.
<p>Normal <strong>emphasized text</strong>.</p><b>
- Placement
- Inline text within paragraphs, headings and list/cell text
- Defaults
- span inherits; strong/b set bold; em/i set italic; u sets underline.
Use style/style-name for supported typography. Explicit false/normal values can override inherited emphasis. Styles must name registered or standard font faces.
<p>Normal <b>emphasized text</b>.</p><em>
- Placement
- Inline text within paragraphs, headings and list/cell text
- Defaults
- span inherits; strong/b set bold; em/i set italic; u sets underline.
Use style/style-name for supported typography. Explicit false/normal values can override inherited emphasis. Styles must name registered or standard font faces.
<p>Normal <em>emphasized text</em>.</p><i>
- Placement
- Inline text within paragraphs, headings and list/cell text
- Defaults
- span inherits; strong/b set bold; em/i set italic; u sets underline.
Use style/style-name for supported typography. Explicit false/normal values can override inherited emphasis. Styles must name registered or standard font faces.
<p>Normal <i>emphasized text</i>.</p><u>
- Placement
- Inline text within paragraphs, headings and list/cell text
- Defaults
- span inherits; strong/b set bold; em/i set italic; u sets underline.
Use style/style-name for supported typography. Explicit false/normal values can override inherited emphasis. Styles must name registered or standard font faces.
<p>Normal <u>emphasized text</u>.</p><a>
- Placement
- Inline text
- Defaults
- Inherited appearance.
Links remain native PDF links. Unsupported URI schemes are rejected. Link text may use supported inline formatting.
| Attribute | Accepted input / meaning |
|---|---|
href | Required HTTP, HTTPS or mailto destination |
title | Optional descriptive title |
<p><a href="https://example.com/help" title="Help">Contact support</a></p><br>
- Placement
- Inline text
- Defaults
- Explicit line change within the current text block.
Void HTML element; no children. Use another p for a new paragraph.
<p>First line<br>Second line</p><page-number>
- Placement
- Inline text, including header/footer
- Defaults
- Dynamic current/total generated-letter page number.
Empty elements with paired closing tags. Counts exclude appended attachment pages. They do not accept text children.
<p>Page <page-number></page-number> of <page-count></page-count></p><page-count>
- Placement
- Inline text, including header/footer
- Defaults
- Dynamic current/total generated-letter page number.
Empty elements with paired closing tags. Counts exclude appended attachment pages. They do not accept text children.
<p>Page <page-number></page-number> of <page-count></page-count></p><page-break>
- Placement
- Body flow only
- Defaults
- Starts a new body page.
Empty, paired closing tag; no attributes including style/style-name. Not allowed inside tables, fixed regions, signatures, canvases or columns.
<main><p>First page</p><page-break></page-break><p>Second page</p></main><img>
- Placement
- Standalone block, supported region/rich cell, logo or image watermark
- Defaults
- Body fitting box up to 60 × 40 mm; region-specific defaults elsewhere; aspect ratio preserved.
PNG/JPEG/restricted static SVG. CSS dimensions override attributes. Percentages use available region dimensions. Width alone permits natural fitted height. No URL/file fetch, inline text images or image background-color.
| Attribute | Accepted input / meaning |
|---|---|
src | Required asset:name reference to supplied bytes |
width | Positive mm/pt/px/% length; unitless means px at 96 dpi |
height | Positive mm/pt/px/% length; unitless means px at 96 dpi |
alt | Image description used in tagged output |
<img src="asset:chart" width="70mm" alt="Comparison of previous and new rates"><ul>
- Placement
- Supported block content
- Defaults
- Unordered bullets / ordered numbering; each nested list has independent numbering/indentation.
Direct li children with inline text and optional nested lists. Arbitrary paragraph/image/table blocks inside li are unsupported.
<ul><li>First item</li><li>Second item<ul><li>Detail</li></ul></li></ul><ol>
- Placement
- Supported block content
- Defaults
- Unordered bullets / ordered numbering; each nested list has independent numbering/indentation.
Direct li children with inline text and optional nested lists. Arbitrary paragraph/image/table blocks inside li are unsupported.
<ol><li>First item</li><li>Second item<ul><li>Detail</li></ul></li></ol><li>
- Placement
- Direct child of ul or ol
- Defaults
- Inline formatted item text.
Place text before child ul/ol lists; text after a child list is rejected.
<li>Item text<ul><li>Nested text</li></ul></li><table>
- Placement
- Supported regions/containers, outside another table
- Defaults
- Equal weights; ordinary row keeps prefer keeping a row together; optional theme table appearance.
One optional repeating thead row plus body rows. Define tbody for grouped rows. Spans must occupy a valid grid. No nested tables/page breaks, including through components.
| Attribute | Accepted input / meaning |
|---|---|
column-weights | Comma-separated positive finite relative column weights |
row-keep | auto, prefer or always |
<table column-weights="2,1"><thead><tr><th>Item</th><th>Price</th></tr></thead><tbody><tr><td>Service</td><td>12.50</td></tr></tbody></table><thead>
- Placement
- Child of table
- Defaults
- Optional repeating header section.
Exactly one logical tr header row; th/td cells may span columns. Header and body span grids are independent. Keep rules intended for body rows are rejected in headers. The keep-together attribute is rejected on thead.
<thead><tr><th>Item</th><th>Price</th></tr></thead><tbody>
- Placement
- Child of table
- Defaults
- Body row group; optional inherited cell/text appearance.
Multiple groups can define explicit row grouping. Spans must stay within their legal grid/group constraints.
| Attribute | Accepted input / meaning |
|---|---|
keep-together | auto, prefer or always; applies to this body row group |
<tbody keep-together="prefer"><tr><td>Related row</td></tr></tbody><tr>
- Placement
- Direct child of thead/tbody or supported table structure
- Defaults
- Inherits table row policy.
Direct th/td cells only. Template data-each/data-as/data-if may select or repeat real rows. Header row keep overrides are rejected.
| Attribute | Accepted input / meaning |
|---|---|
row-keep | auto, prefer or always; body rows only |
keep-with-next | auto, prefer or always; body rows only |
<tr row-keep="prefer"><td>Value</td><td>12.50</td></tr><th>
- Placement
- Direct child of tr
- Defaults
- 1 × 1; th has bold semantic default below named/explicit overrides.
Either inline text or supported rich blocks. Borders/padding/background/vertical alignment inherit by field. Text mixed with child block elements is rejected.
| Attribute | Accepted input / meaning |
|---|---|
colspan | Positive integer number of columns |
rowspan | Positive integer number of rows |
<th colspan="2"><p>Spanning cell</p><ul><li>Detail</li></ul></th><td>
- Placement
- Direct child of tr
- Defaults
- 1 × 1; th has bold semantic default below named/explicit overrides.
Either inline text or supported rich blocks. Borders/padding/background/vertical alignment inherit by field. Text mixed with child block elements is rejected.
| Attribute | Accepted input / meaning |
|---|---|
colspan | Positive integer number of columns |
rowspan | Positive integer number of rows |
<td colspan="2"><p>Spanning cell</p><ul><li>Detail</li></ul></td><canvas>
- Placement
- Supported block flow
- Defaults
- Coordinates start at the canvas upper-left corner within body flow.
Bounded indivisible flow unit containing positioned box children. Boxes must fit; overlaps are intentional in list paint order. No automatic splitting, browser absolute positioning or page breaks.
| Attribute | Accepted input / meaning |
|---|---|
width-mm | Optional finite positive width; defaults to available region width |
height-mm | Required finite positive canvas height |
<canvas width-mm="160" height-mm="30"><box id="address" x-mm="0" y-mm="0" width-mm="75" height-mm="25"><p>Example address</p></box></canvas><columns>
- Placement
- Supported block flow
- Defaults
- 0 mm gap; independent columns.
Column children split the available width by weight and can flow across pages. No automatic text threading/balancing; no explicit page breaks inside columns.
| Attribute | Accepted input / meaning |
|---|---|
gap-mm | Finite nonnegative gap between columns |
<columns gap-mm="6"><column weight="2"><p>Main text</p></column><column weight="1"><p>Side text</p></column></columns><column>
- Placement
- Direct child of columns
- Defaults
- Weight 1.
Independent supported block content and local style. A wider weight does not cause text to flow from another column.
| Attribute | Accepted input / meaning |
|---|---|
weight | Finite positive relative width |
<column weight="2"><p>Column content</p></column><box>
- Placement
- Flowing block, or positioned direct child of canvas
- Defaults
- Ordinary flowing content with optional decoration.
Supports padding, background-color, border and per-edge borders alongside inherited typography. No general browser box model. Inside canvas, box instead declares a bounded positioned rectangle with a unique id, explicit width/height and optional x/y. Its rich content must fit; no page breaks. Decoration CSS applies to flowing box, not the positioned canvas wrapper.
| Attribute | Accepted input / meaning |
|---|---|
id | Canvas box only: Required unique nonblank stable identifier |
x-mm | Canvas box: finite nonnegative x; defaults to 0 |
y-mm | Canvas box: finite nonnegative y; defaults to 0 |
width-mm | Canvas box only: Required finite positive item width |
height-mm | Canvas box only: Required finite positive item height |
<box style="padding:3mm; border:0.5pt solid #12665B; background-color:#F0F7F4"><p>Important information</p></box><component>
- Placement
- Supported block content
- Defaults
- Expands document-local reusable blocks before validation.
Empty element with a paired closing tag. Unknown references and reference cycles fail. Context rules still apply to expanded content.
| Attribute | Accepted input / meaning |
|---|---|
ref | Required name registered through components(...) or the shared model |
<component ref="legal"></component><param>
- Placement
- Inline template content; template mode only
- Defaults
- text formatting unless selected; final template locale applies.
Void HTML tag, no closing tag, children or style/style-name. Wrap with span/strong for styling. Substitution creates literal text, never markup. Supported input type must match the format.
| Attribute | Accepted input / meaning |
|---|---|
key | Required scalar map path |
format | text, date, number or currency |
pattern | Optional formatter pattern |
currency | Optional ISO currency override |
<p>Total: <strong><param key="total" format="currency" currency="EUR"></strong></p><if>
- Placement
- Template content outside table structure
- Defaults
- Selects true branch or direct else branch; no expressions/truthiness.
Only flag is permitted. Use data-if on real table rows/cells. Inactive branches do not require their values/assets.
| Attribute | Accepted input / meaning |
|---|---|
flag | Required map path to an actual Boolean |
<if flag="showNotice"><p>Notice</p><else><p>Standard text</p></else></if><else>
- Placement
- One direct child of if
- Defaults
- Selected when flag is false.
No attributes, including style/style-name. Must be unique and in the supported final branch position.
<if flag="showNotice"><p>Notice</p><else><p>Standard text</p></else></if>