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], [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:

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.
textDecorationstring"underline", "line-through", or "underline line-through".
letterSpacingnumberExtra space between characters, in points.
wordSpacingnumberExtra space between words, in points.
lineHeightnumberLine height as a multiplier of the font size (e.g. 1.4).
leadingnumberExplicit line leading in points — overrides lineHeight when both are set.
textIndentnumberIndent applied to the first line of each paragraph, 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. The string form mirrors the CSS padding / margin shorthand verbatim — write the same value you'd write in a stylesheet.

PropertyTypeDescription
paddingnumber | stringShorthand. See Shorthand expansion below.
paddingTopnumberTop padding (points).
paddingRightnumberRight padding.
paddingBottomnumberBottom padding.
paddingLeftnumberLeft padding.
marginnumber | stringShorthand. See Shorthand expansion below.
marginTopnumberTop margin.
marginRightnumberRight margin.
marginBottomnumberBottom margin.
marginLeftnumberLeft margin.

Shorthand expansion

FormMeaning
"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
4Bare number — same effect as "4", JSON-idiomatic ergonomic shortcut
CSS-faithful vs ergonomic

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

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.

Table border spacing

PropertyTypeDescription
borderSpacingnumber | 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.

PropertyTypeDescription
widthnumberFixed width in points.
heightnumberFixed height in points.
minWidthnumberMinimum width — element grows to at least this.
maxWidthnumberMaximum width — element clips to at most this.
minHeightnumberMinimum height — useful on variable-content labels to stop row drift.
maxHeightnumberMaximum height.

Multi-column layout (in-element)

PropertyTypeDescription
columnCountnumberNumber of columns to flow text into within a single element.
columnGapnumberGap between columns in points.

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.
strokeMiterlimitnumberMiter 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. ". ").
listStylePositionstringinside 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][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 + map pattern 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).