Skip to main content

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:

LayerBehavior
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-size becomes fontSize, margin-top becomes marginTop, border-collapse becomes borderCollapse, text-align becomes textAlign.
  • 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.

ScopeWhat it applies toProperties
ElementParagraphs, headings, table cells, list items, divsTypography, spacing, alignment, background, borders, list symbols, rotation, opacity, position
CanvasShapes and lines inside a canvas blockFill / stroke color, line styling, opacity, text rendering mode, skew, affine transform
DocumentDocument-root defaultsFont 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

PropertyTypeDescription
fontFamilystringNamed font family (must be registered in the document's fonts block). Defaults to Helvetica.
fontSizenumberFont size in points.
colorstringText color (elements) / stroke color (canvas). Hex form, e.g. "#333333" or "#33333380" for 50% opacity.
fontWeightstringCSS values: normal, bold, bolder, lighter, or 100900.
fontStylestringnormal, italic, oblique.
underlinebooleanUnderlines the text.
letterSpacingnumberExtra space between characters, in points. (CSS-aligned name; characterSpacing is the legacy alias.)
wordSpacingnumberExtra space between words, in points.
lineHeightnumberLine height in points.
opacitynumber0.0 – 1.0. Applies to elements, canvas paths, and document-level.

Alignment

PropertyTypeValues
textAlignstringleft, right, center, justify
verticalAlignstringtop, middle, bottom, baseline (cell or row).

Spacing

Padding controls space inside an element's box; margin controls space outside.

PropertyTypeDescription
paddingnumberShorthand: all four sides.
paddingTopnumberTop padding (points).
paddingRightnumberRight padding.
paddingBottomnumberBottom padding.
paddingLeftnumberLeft padding.
marginnumberShorthand: all four sides.
marginTopnumberTop margin.
marginRightnumberRight margin.
marginBottomnumberBottom margin.
marginLeftnumberLeft margin.

Backgrounds

PropertyTypeDescription
backgroundColorstringBackground fill for the element box (or canvas shape).
backgroundobjectFull background descriptor — typically { "color": "#…" }.
backgroundImagestringDocument-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).

PropertyTypeDescription
borderstringCSS shorthand — applies to all four sides. e.g. "1pt solid #000", "none".
borderTopstringTop border (CSS shorthand).
borderRightstringRight border (CSS shorthand).
borderBottomstringBottom border (CSS shorthand).
borderLeftstringLeft border (CSS shorthand).
borderRadiusnumberCorner radius (pt) — all four corners.
borderTopLeftRadiusnumberPer-corner radius (pt). Also borderTopRightRadius, borderBottomRightRadius, borderBottomLeftRadius.
borderCollapsestringcollapse / 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

PropertyTypeDescription
relativePositionfloat[4][left, right, top, bottom] shift relative to natural layout position.
fixedPositionobject{ 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.

PropertyTypeDescription
rotatenumberRotation angle in degrees (applies to elements like paragraphs and divs).
rotationPointX, rotationPointYnumberCustom rotation pivot.
rotationInitialHeight, rotationInitialWidthnumberLayout-reservation hints so rotated content gets the right bounding box.
skewnumber[1 or 2][skewX] or [skewX, skewY] in degrees. Canvas scope only — applies to the coordinate system.
transformnumber[6]Affine matrix [a, b, c, d, e, f] concatenated onto the canvas CTM.
textRenderingModestringfill, 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>.

PropertyTypeDescription
strokestringPath stroke color, hex.
strokeWidthnumberStroke width in points.
fillstringFill color for the path/shape, hex.
strokeDasharraynumber[]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.
strokeDashoffsetnumberStarting offset into the dash pattern.
strokeLinecapstringbutt (default), round, or square. Applies to any stroked shape (paths, lines, arcs, circles) — use round to soften dotted patterns.
strokeLinejoinstringmiter (default), round, or bevel.
miterLimitnumberMiter cutoff ratio.

List symbol controls

These apply to ol / ul blocks.

PropertyTypeDescription
symbolstringMarker character, e.g. "1", "a", "i", "•".
symbolAlignstringMarker alignment within its reserved cell.
symbolIndentnumberIndent applied before the marker.
symbolOrdinalnumberStarting ordinal value for ordered lists.
symbolPrefixstringText appended before each marker.
symbolSuffixstringText appended after each marker (e.g. ". ").
symbolPositionstringinside or outside.
listStartnumberStarting 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 + map pattern 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).