Styles
The styles object defines named style definitions referenced from any content element via the "style" property. This keeps formatting consistent and your document definition DRY.
{
"document": {
"styles": {
"h1": { "fontSize": 22, "fontWeight": "bold", "color": "#1A1A2E" },
"body": { "fontSize": 10, "color": "#333333", "textAlign": "justify" }
},
"content": [
{ "p": "Main Heading", "style": "h1" },
{ "p": "Body paragraph text.", "style": "body" }
]
}
}
A style can be applied to any block element (paragraph, heading, table, cell, list, list item, canvas command, watermark). Inline [b], [i], [fontcolor], etc. tags layered inside text override the applied style for the tagged span — see Inline Tags.
How style validation works
Style enforcement is intentionally asymmetric — strict at authoring time, lenient at render time:
| Layer | Behavior |
|---|---|
| Editor / IDE (via the JSON schema) | Unknown style keys get a red squiggle. The schema enumerates every valid property name; typos like fontWieght or colour are flagged on the line you type them. |
Runtime (document rendering) | Unknown style keys are silently ignored. A typo never breaks a production render — the affected property simply doesn't apply, the rest of the style still does. |
The reasoning: catch typos before deploy (in the editor), but never let them break customer documents at runtime. Case is treated leniently at runtime too — FontWeight, fontweight, and fontWeight all resolve to the same property (CSS spec), but IDE autocomplete always supplies the canonical camelCase form.
For structural keys (content discriminators like p, table, shapes) the contract is strict at both layers — those define what gets rendered, not how it looks, so a silent drop would produce empty output.
Naming follows CSS and SVG
Property names mirror the CSS and SVG specs so anyone fluent in HTML/CSS authors DocPayload styles by ear. The translation is mechanical:
- Keys: CSS kebab-case → JSON camelCase.
font-sizebecomesfontSize,margin-topbecomesmarginTop,border-collapsebecomesborderCollapse,text-alignbecomestextAlign. - Values: lowercase, matching CSS.
textAlign: "center",borderCollapse: "collapse",verticalAlign: "middle",strokeLinecap: "round",fontWeight: "bold",fontStyle: "italic". - Canvas / shape properties follow SVG presentation attributes:
stroke,strokeWidth,strokeDasharray,strokeDashoffset,strokeLinecap,strokeLinejoin,fill. See Canvas-only properties. - Borders use the CSS shorthand string —
border: "1pt solid #000",borderTop: "2pt dashed #FF0000",borderBottom: "none". Components (width, style, color) may appear in any order; missing parts fall back to the engine defaults (1pt / solid / black). Per-side opacity rides in the color's alpha channel via 8-digit hex (#RRGGBBAA). Per-corner radius lives on its own properties (borderRadius,borderTopLeftRadius, etc.) — same shape CSS uses. - Engine accepts both cases at parse time (case-insensitive) —
"CENTER"and"center"render identically — but lowercase is canonical in docs, fixtures, and IDE autocomplete.
Where styles apply
Style properties fall into three scopes. Most are usable on elements; some are canvas-only; a handful are document-level.
| Scope | What it applies to | Properties |
|---|---|---|
| Element | Paragraphs, headings, table cells, list items, divs | Typography, spacing, alignment, background, borders, list symbols, rotation, opacity, position |
| Canvas | Shapes and lines inside a canvas block | Fill / stroke color, line styling, opacity, text rendering mode, skew, affine transform |
| Document | Document-root defaults | Font family, font size, font color, page-wide background, margins, opacity |
Styles only carry visual concerns. Structural attributes that change a node's footprint in its parent — table-cell colspan / rowspan, content [outline](/document-definition/diagnostics) toggles — live on the node itself, not in a style block. That mirrors HTML, where colspan="2" is a <td> attribute, not a CSS rule.
Typography
| Property | Type | Description |
|---|---|---|
fontFamily | string | Named font family (must be registered in the document's fonts block). Defaults to Helvetica. |
fontSize | number | Font size in points. |
color | string | Text color (elements) / stroke color (canvas). Hex form, e.g. "#333333" or "#33333380" for 50% opacity. |
fontWeight | string | CSS values: normal, bold, bolder, lighter, or 100–900. |
fontStyle | string | normal, italic, oblique. |
underline | boolean | Underlines the text. |
letterSpacing | number | Extra space between characters, in points. (CSS-aligned name; characterSpacing is the legacy alias.) |
wordSpacing | number | Extra space between words, in points. |
lineHeight | number | Line height in points. |
opacity | number | 0.0 – 1.0. Applies to elements, canvas paths, and document-level. |
Alignment
| Property | Type | Values |
|---|---|---|
textAlign | string | left, right, center, justify |
verticalAlign | string | top, middle, bottom, baseline (cell or row). |
Spacing
Padding controls space inside an element's box; margin controls space outside.
| Property | Type | Description |
|---|---|---|
padding | number | Shorthand: all four sides. |
paddingTop | number | Top padding (points). |
paddingRight | number | Right padding. |
paddingBottom | number | Bottom padding. |
paddingLeft | number | Left padding. |
margin | number | Shorthand: all four sides. |
marginTop | number | Top margin. |
marginRight | number | Right margin. |
marginBottom | number | Bottom margin. |
marginLeft | number | Left margin. |
Backgrounds
| Property | Type | Description |
|---|---|---|
backgroundColor | string | Background fill for the element box (or canvas shape). |
background | object | Full background descriptor — typically { "color": "#…" }. |
backgroundImage | string | Document-level only — a page-wide background image asset path. |
Borders
Each side is an independent CSS shorthand string of the form "<width> <style> <color>" — components may appear in any order, missing parts fall back to the engine defaults (1pt / solid / black). Use "none" to remove a side. Opacity rides in the color's alpha channel via 8-digit hex (#RRGGBBAA).
| Property | Type | Description |
|---|---|---|
border | string | CSS shorthand — applies to all four sides. e.g. "1pt solid #000", "none". |
borderTop | string | Top border (CSS shorthand). |
borderRight | string | Right border (CSS shorthand). |
borderBottom | string | Bottom border (CSS shorthand). |
borderLeft | string | Left border (CSS shorthand). |
borderRadius | number | Corner radius (pt) — all four corners. |
borderTopLeftRadius | number | Per-corner radius (pt). Also borderTopRightRadius, borderBottomRightRadius, borderBottomLeftRadius. |
borderCollapse | string | collapse / separate for tables. |
Supported <style> keywords: solid, dashed, dotted, double, groove, ridge, inset, outset, none (case-insensitive).
Pages themselves support borders via pageSetup.borderTop/Right/Bottom/Left — same CSS shorthand string.
Position
| Property | Type | Description |
|---|---|---|
relativePosition | float[4] | [left, right, top, bottom] shift relative to natural layout position. |
fixedPosition | object | { pageNumber, left, bottom, width, height } — pins the element to absolute page coordinates. |
Transforms — rotation, skew, affine
Real transformation primitives, useful for vertical sidebars, stamped overlays, edge-mounted barcodes, and outlined banners.
| Property | Type | Description |
|---|---|---|
rotate | number | Rotation angle in degrees (applies to elements like paragraphs and divs). |
rotationPointX, rotationPointY | number | Custom rotation pivot. |
rotationInitialHeight, rotationInitialWidth | number | Layout-reservation hints so rotated content gets the right bounding box. |
skew | number[1 or 2] | [skewX] or [skewX, skewY] in degrees. Canvas scope only — applies to the coordinate system. |
transform | number[6] | Affine matrix [a, b, c, d, e, f] concatenated onto the canvas CTM. |
textRenderingMode | string | fill, stroke, fillstroke, invisible, fillclip, strokeclip, fillstrokeclip, clip. Use stroke for outlined text effects. |
Example — angled rubber-stamp overlay
{
"styles": {
"stamp": {
"fontSize": 28,
"fontWeight": "bold",
"color": "#7A1F2A",
"letterSpacing": 4,
"rotate": -15,
"opacity": 0.55,
"textAlign": "center"
}
},
"content": [
{ "p": "AWAITING PAYMENT", "style": "stamp" }
]
}
Example — vertical sidebar text
{
"styles": {
"sidebar": {
"fontSize": 14,
"fontWeight": "bold",
"color": "#1B5E3F",
"letterSpacing": 8,
"rotate": 90
}
},
"content": [
{ "p": "DOCUMENT OFFICIEL", "style": "sidebar" }
]
}
Canvas-only properties
These apply inside a content item's shapes[].style references (shapes and lines on the SVG-aligned canvas). Names follow the SVG presentation attributes so anyone fluent in SVG can author canvas styles by ear — stroke, fill, strokeDasharray, strokeLinecap, strokeLinejoin are the same names you'd use on an SVG <path>.
| Property | Type | Description |
|---|---|---|
stroke | string | Path stroke color, hex. |
strokeWidth | number | Stroke width in points. |
fill | string | Fill color for the path/shape, hex. |
strokeDasharray | number[] | Dash pattern, e.g. [5, 2] (dash), [0.5, 2.5] (dots, pair with strokeLinecap: "round"). Use [0] or [] to reset to solid — the PDF canvas state is sticky, so an earlier dash pattern persists until explicitly overridden. |
strokeDashoffset | number | Starting offset into the dash pattern. |
strokeLinecap | string | butt (default), round, or square. Applies to any stroked shape (paths, lines, arcs, circles) — use round to soften dotted patterns. |
strokeLinejoin | string | miter (default), round, or bevel. |
miterLimit | number | Miter cutoff ratio. |
List symbol controls
These apply to ol / ul blocks.
| Property | Type | Description |
|---|---|---|
symbol | string | Marker character, e.g. "1", "a", "i", "•". |
symbolAlign | string | Marker alignment within its reserved cell. |
symbolIndent | number | Indent applied before the marker. |
symbolOrdinal | number | Starting ordinal value for ordered lists. |
symbolPrefix | string | Text appended before each marker. |
symbolSuffix | string | Text appended after each marker (e.g. ". "). |
symbolPosition | string | inside or outside. |
listStart | number | Starting index for an ordered list. |
Worked examples
Layered heading hierarchy h1–h5
{
"styles": {
"h1": {
"fontSize": 18, "fontWeight": "bold", "color": "#FFFFFF", "letterSpacing": 2,
"backgroundColor": "#0F2A4A",
"paddingTop": 10, "paddingRight": 14, "paddingBottom": 10, "paddingLeft": 14,
"marginTop": 18, "marginBottom": 8
},
"h2": {
"fontSize": 12, "fontWeight": "bold", "color": "#0F2A4A", "letterSpacing": 1,
"borderBottom": "1pt solid #0F2A4A",
"paddingBottom": 4,
"marginTop": 14, "marginBottom": 6
},
"h3": { "fontSize": 10.5, "fontWeight": "bold", "color": "#C66B1B", "marginTop": 10, "marginBottom": 3 },
"h4": { "fontSize": 9.5, "fontWeight": "bold", "fontStyle": "italic", "color": "#1A1A2E" },
"h5": { "fontSize": 8.5, "fontWeight": "bold", "color": "#666666", "letterSpacing": 2 }
}
}
Tier-coded data badges
Use inline highlight/color in map expressions for per-row variation in data-driven tables.
{
"data": {
"tiers": [
{ "name": "Public", "badge": "[hl, #E8F4EC][fontcolor, #1E6F3A][b] PUBLIC [/b][/fontcolor][/hl]" },
{ "name": "Restricted", "badge": "[hl, #FCEEF0][fontcolor, #7A1F2A][b] RESTRICTED [/b][/fontcolor][/hl]" }
]
}
}
Encrypted-document banner with stroked text
{
"styles": {
"banner": {
"fontSize": 36,
"fontWeight": "bold",
"color": "#7A1F2A",
"letterSpacing": 6,
"textRenderingMode": "stroke",
"strokeWidth": 0.5,
"textAlign": "center",
"opacity": 0.3
}
}
}
Style inheritance
- A style applied to a parent table propagates to its data-driven body cells (the
source+mappattern creates cells with no explicit style; they inherit the table-level style). - Inline tags inside text override the applied style for the tagged span only.
- For per-cell variation in data-driven tables, bake inline tags into a data field and reference it via
$item.fieldName— see Data Injection.
See Inline Tags for the inline-formatting tag reference and Page Setup for page-level styling (borders, backgrounds, margins).