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], [color], etc. tags layered inside text override the applied style for the tagged span — see Shortcodes.
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. |
textDecoration | string | "underline", "line-through", or "underline line-through". |
letterSpacing | number | Extra space between characters, in points. |
wordSpacing | number | Extra space between words, in points. |
lineHeight | number | Line height as a multiplier of the font size (e.g. 1.4). |
leading | number | Explicit line leading in points — overrides lineHeight when both are set. |
textIndent | number | Indent applied to the first line of each paragraph, 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. The string form mirrors the CSS padding / margin shorthand verbatim — write the same value you'd write in a stylesheet.
| Property | Type | Description |
|---|---|---|
padding | number | string | Shorthand. See Shorthand expansion below. |
paddingTop | number | Top padding (points). |
paddingRight | number | Right padding. |
paddingBottom | number | Bottom padding. |
paddingLeft | number | Left padding. |
margin | number | string | Shorthand. See Shorthand expansion below. |
marginTop | number | Top margin. |
marginRight | number | Right margin. |
marginBottom | number | Bottom margin. |
marginLeft | number | Left margin. |
Shorthand expansion
| Form | Meaning |
|---|---|
"4" | All four sides = 4pt — CSS-faithful |
"4 8" | Top/Bottom = 4 · Left/Right = 8 — CSS-faithful |
"4 8 6" | Top = 4 · Left/Right = 8 · Bottom = 6 — CSS-faithful |
"4 8 6 2" | Top = 4 · Right = 8 · Bottom = 6 · Left = 2 (clockwise from top) — CSS-faithful |
4 | Bare number — same effect as "4", JSON-idiomatic ergonomic shortcut |
The string forms match CSS exactly — same syntax, same expansion. The bare-number form ("padding": 4) is not in the CSS spec (CSS requires units: padding: 4px;); we accept it as a JSON-idiomatic shortcut for the common all-sides case. Use the string form if you prefer one-shape-fits-all CSS alignment.
Per-side overrides (paddingTop, marginLeft, etc.) win over the shorthand when both are set on the same style — same precedence as CSS:
{
"callout": {
"padding": "6 12",
"paddingLeft": 24
}
}
→ top/bottom = 6, right = 12, left = 24.
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.
Table border spacing
| Property | Type | Description |
|---|---|---|
borderSpacing | number | number[2] | Gap between adjacent cells when borderCollapse is separate. Single value applies to both axes; [h, v] sets horizontal and vertical independently. |
Dimensions
Apply fixed or bounded dimensions to elements. PDF honors these on every block element; DOCX honors them on table rows.
| Property | Type | Description |
|---|---|---|
width | number | Fixed width in points. |
height | number | Fixed height in points. |
minWidth | number | Minimum width — element grows to at least this. |
maxWidth | number | Maximum width — element clips to at most this. |
minHeight | number | Minimum height — useful on variable-content labels to stop row drift. |
maxHeight | number | Maximum height. |
Multi-column layout (in-element)
| Property | Type | Description |
|---|---|---|
columnCount | number | Number of columns to flow text into within a single element. |
columnGap | number | Gap between columns in points. |
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. |
strokeMiterlimit | 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. ". "). |
listStylePosition | 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][color, #1E6F3A][b] PUBLIC [/b][/color][/hl]" },
{ "name": "Restricted", "badge": "[hl, #FCEEF0][color, #7A1F2A][b] RESTRICTED [/b][/color][/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). - Shortcodes inside text override the applied style for the tagged span only.
- For per-cell variation in data-driven tables, bake Shortcodes into a data field and reference it via
$item.fieldName— see Data Binding.
See Shortcodes for the inline-formatting tag reference and Page Setup for page-level styling (borders, backgrounds, margins).