SVG
Draw shapes, text, and images at precise coordinates — diagrams, charts, icons, seals, decorative chrome. You author them the way you already know: as SVG. Element names and properties mirror SVG — cx/cy/r, x1/y1/x2/y2, d, fill, stroke, viewBox — so an SVG snippet transfers with minimal translation. Everything renders as native vector in both PDF and DOCX — same JSON, same output, zero raster images.
Live example
A real-world architecture diagram: a hexagon for the edge service, rounded rectangles for compute, ellipse-on-rectangle cylinders for databases, color-coded connectors. Open the Template tab to see the JSON.
- Output
- Template
- Data
The svg block
An SVG graphic is a Content item with an svg block — a viewBox plus a list of children. It reads like an <svg> root element:
{
"svg": {
"viewBox": [0, 0, 24, 24],
"children": [
{ "path": { "d": "M12 2 C8 2 5 5 5 9 c0 5 7 13 7 13 s7-8 7-13 c0-4-3-7-7-7 Z", "style": "pin" } },
{ "circle": { "cx": 12, "cy": 9, "r": 2.5, "style": "hole" } }
]
}
}
| Property | Type | Default | Description |
|---|---|---|---|
viewBox | [W, H] or [minX, minY, W, H] | auto from children | Coordinate extents as a numeric array — the same convention as table / columns widths. Omit to derive the tight box from the children (paths and curves included). |
width | number | viewBox scale | Rendered display width in points. The viewBox stays the coordinate space the children are drawn in; width scales the graphic to this size. Omit to render at 1 unit = 1 point. |
height | number | derived from aspect | Rendered display height in points. Give one of width/height to scale uniformly (the other follows the viewBox aspect), or both. |
children | array | — | Drawing elements (see below). |
title | string | — | Accessible name for the whole graphic (screen readers, tagged-PDF /Alt, DOCX drawing title). |
desc | string | — | Longer accessible description. |
Pasting a real icon? Keep its
ddata andviewBoxexactly as-is, convert theviewBoxstring to an array, and addwidthfor the size you want — e.g. a0 0 1024 1024glyph with"width": 24renders as a 24 pt icon. No coordinate math.
Each child is { "<element>": { …props } } — one drawing element keyed by its name, exactly as SVG nests elements inside <svg>. Every element carries a style reference into document.styles for its fill / stroke / etc.
Coordinates are box-relative, top-left origin — x grows right, y grows down. A 4-number viewBox ([minX, minY, W, H]) shifts the origin the same way SVG does, so negative author-coordinates land inside the box.
Keep coordinates local. The graphic is its own coordinate box — never reach for page-absolute positions inside it. With
viewBoxomitted, the box is derived from the children, so a single stray page-sizedyinflates the derived box and the whole graphic shrinks toward nothing. Position the block on the page like any other content item; position children within the box.
Centering the block
An svg block spans its own box and ignores the margins and textAlign of paragraph styles. To center (or right-align) a graphic within the content width, make the viewBox the full content width and shift the children with a g translate:
{
"svg": {
"viewBox": [512, 160],
"children": [
{ "g": { "translate": [176, 0], "children": [ { "circle": { "cx": 80, "cy": 80, "r": 78, "style": "seal" } } ] } }
]
}
}
(512 − 160) / 2 = 176 centers a 160-unit graphic in a 512-unit box; a translate of 352 right-aligns it.
Elements
Every element renders identically in PDF and DOCX — same JSON, same output.
- Output
- Template
- Data
The vocabulary is standard SVG plus a few DocPayload conveniences:
| Category | Elements | |
|---|---|---|
| SVG primitives | rect, circle, ellipse, line, polygon, polyline, path | Standard SVG. |
| SVG content | text, textPath, image | Standard SVG. |
| SVG grouping | g, use | Standard SVG — group under one transform; instantiate a reusable symbol. |
| Shape shortcuts (extension) | arc, triangle, diamond, pentagon, hexagon, octagon, plus, parallelogram, trapezoid, rightArrow, leftArrow, upArrow, downArrow, chevron | Convenience shapes SVG can express only via hand-computed polygon points or path arcs. Each fits a width × height box you supply; the vertices are derived for you. |
| Barcode (extension) | barcode | A render-time barcode generator — no SVG equivalent. Encodes a payload (often $data-bound) as native vector. |
SVG vocabulary + DocPayload extensions. Everything in the first three rows is standard SVG. The shape shortcuts and
barcodeare DocPayload additions layered on top — they live alongside the SVG elements in the samechildren, so you never leave the SVG model to reach them. Usepath/polygonwhen you want strict SVG; reach for the shortcuts andbarcodewhen they save you the arithmetic.
The path / textPath elements accept raw SVG d strings, making them the most flexible primitive — anything you can draw in SVG (Beziers, arcs, compound paths, decorative flourishes) transfers directly. See the Patterns Gallery tutorial for a full reference of decorative compositions (mandala, sunburst, Greek key, Lissajous, guilloché).
Drawing elements
Each element is { "<name>": { …props } }. Every element carries a style reference into document.styles.
Geometry primitives
Rectangle
{ "rect": { "x": 100, "y": 100, "width": 150, "height": 80, "rx": 6, "ry": 6, "style": "card" } }
rx / ry are optional corner radii — omit them for square corners.
Circle
{ "circle": { "cx": 200, "cy": 100, "r": 30, "style": "node" } }
Ellipse
{ "ellipse": { "cx": 200, "cy": 100, "rx": 55, "ry": 6, "style": "dbCap" } }
Shape shortcuts (extension)
triangle, diamond, pentagon, hexagon, octagon, plus, parallelogram, trapezoid. All take x, y, width, height; the vertices fit inside that box. (In strict SVG these would be a <polygon> with hand-computed points.)
{ "triangle": { "x": 0, "y": 0, "width": 80, "height": 80, "style": "shape" } }
{ "diamond": { "x": 110, "y": 0, "width": 80, "height": 80, "style": "shape" } }
{ "pentagon": { "x": 220, "y": 0, "width": 80, "height": 80, "style": "shape" } }
{ "hexagon": { "x": 330, "y": 0, "width": 80, "height": 80, "style": "shape" } }
{ "octagon": { "x": 0, "y": 100, "width": 80, "height": 80, "style": "shape" } }
{ "plus": { "x": 110, "y": 100, "width": 80, "height": 80, "style": "shape" } }
{ "parallelogram": { "x": 220, "y": 100, "width": 80, "height": 80, "style": "shape" } }
{ "trapezoid": { "x": 330, "y": 100, "width": 80, "height": 80, "style": "shape" } }
Directional arrows follow the same rule — rightArrow, leftArrow, upArrow, downArrow, chevron. The orientation is encoded in the name; the renderer adjusts the vertex math.
{ "rightArrow": { "x": 0, "y": 0, "width": 90, "height": 60 } }
{ "leftArrow": { "x": 110, "y": 0, "width": 90, "height": 60 } }
{ "upArrow": { "x": 220, "y": 0, "width": 60, "height": 90 } }
{ "downArrow": { "x": 290, "y": 0, "width": 60, "height": 90 } }
{ "chevron": { "x": 360, "y": 0, "width": 80, "height": 60 } }
Group g
Groups children under a shared transform and a cascaded default style, exactly like SVG's <g>. Children draw in the group's local coordinates.
| Property | Type | Description |
|---|---|---|
children | array | Child elements, any of the vocabulary on this page — groups nest. |
translate | [tx, ty] | Offset in points. |
rotate | number | Rotation in degrees. |
skew | [x] or [x, y] | Skew in degrees. |
scale | [sx, sy] | Scale factors — non-negative; mirroring via a negative scale is not supported. |
transform | [a, b, c, d, e, f] | Raw affine matrix, applied last. |
style | string | Named style cascaded to children that declare none. |
Transforms compose in SVG order: translate → rotate → skew → scale, then the raw matrix.
DOCX note. Word groups carry translate, scale, and rotate (pivoting on the group's center).
skewand the rawtransformmatrix aren't expressible on a Word group and are dropped there — the PDF honors them in full. When a graphic must match across both formats, compose fromtranslate/rotate/scaleonly.
Labeled nodes (group a shape + label)
A diagram node — a shape with a centered label — is a g group: the shape plus a text centered in the same box. Children draw in the group's local coordinates, so translate places the node and the group's style cascades to children that declare none (here, the shape inherits the node fill while the label keeps its own white-text style).
{ "g": {
"translate": [30, 85],
"style": "node",
"children": [
{ "hexagon": { "x": 0, "y": 0, "width": 110, "height": 50 } },
{ "text": { "x": 0, "y": 25, "width": 110, "baseline": "middle", "text": "API Gateway", "style": "nodeLabel" } }
]
} }
Centre the label vertically with baseline: "middle" and y at the box's mid-height (here y: 25 for a 50-tall box) — no y = height/2 − fontSize/2 arithmetic. When the same node recurs across a diagram (the common case), define it once as a symbol and use it with per-instance data — see order-lifecycle-states.json and org-chart.json.
Live example — architecture-diagram.json (a hexagon edge node as a g, plus four arch-node symbols instantiated via use).
Polygon
Closed polygon defined by N points. Useful for stars, badges, custom flowchart shapes. Auto-closed (last vertex back to first).
{
"polygon": {
"points": [
{ "x": 100, "y": 10 },
{ "x": 140, "y": 40 },
{ "x": 125, "y": 90 },
{ "x": 75, "y": 90 },
{ "x": 60, "y": 40 }
],
"style": "star"
}
}
Polyline
An open run of connected segments — same vertex list as polygon, but not closed back to the first point. Use it for zigzags, open paths, sparkline strokes, and axis ticks where a closing edge would be wrong.
{
"polyline": {
"points": [
{ "x": 10, "y": 60 }, { "x": 50, "y": 20 },
{ "x": 90, "y": 60 }, { "x": 130, "y": 20 }, { "x": 170, "y": 60 }
],
"style": "trace"
}
}
Lines and arcs
Line
{ "line": { "x1": 50, "y1": 50, "x2": 200, "y2": 150, "style": "connector" } }
Arc (extension)
Sweep from startAngle to endAngle (degrees, CCW from +x) around (cx, cy). A shortcut for a path with an A command when you'd rather give a center and angles than compute arc endpoints.
{ "arc": { "cx": 200, "cy": 200, "r": 60, "startAngle": 0, "endAngle": 180, "style": "arc" } }
Paths & text on path
Path
Arbitrary SVG path data via the d attribute. Supports the standard SVG commands: M/m (moveto), L/l (lineto), H/h / V/v (horizontal/vertical lineto), C/c / S/s (cubic Bezier + smooth), Q/q / T/t (quadratic Bezier + smooth), A/a (elliptical arc), Z/z (close path). Strokes and/or fills based on which color properties the style supplies (stroke → stroke, fill → fill, both → fill+stroke).
{ "path": { "d": "M 0 50 Q 100 0 200 50 T 400 50", "style": "wave" } }
Compound paths with holes — set fillRule on the element (beside d) to evenodd so overlapping subpaths cut holes instead of filling solid. This is what pasted Material / Font Awesome / Bootstrap icons rely on to keep their counters. fillRule lives on the element, not the style, because winding is intrinsic to the path data. PDF honors it fully; Word renders nonzero winding and logs a diagnostic (holes may fill).
{ "path": { "d": "M20 20H180V100H20Z M60 40H140V80H60Z", "fillRule": "evenodd", "style": "icon" } }
Full circle as two semicircular arcs:
{ "path": { "d": "M 100 6 A 94 94 0 0 1 100 194 A 94 94 0 0 1 100 6", "style": "outerRing" } }
textPath
Flows text along a path with per-glyph rotation. The path itself is not drawn — pair with a path element using the same d if you want a visible curve too.
| Property | Type | Description |
|---|---|---|
d | string | SVG path data (same syntax as path). |
text | string | Text to flow; supports Shortcodes ([b], [i], [u], [s], [sub], [sup], [mark], [color], [fontsize], [caps], [font, Family], …) and multi-line via [br] / [br, n] — svg text never wraps, so explicit breaks are the line boundaries and each line aligns independently. Shaped at render time — complex scripts join/stack correctly (see Multi-script text and seals). |
alignment | enum | start (default) · middle · end — anchors the text along the path. |
startOffset | number | Distance in points from path start before the first glyph. |
side | enum | above (default) — baseline on path; below — glyph hangs below the path. |
style | string | Text style. |
{
"textPath": {
"d": "M 24 100 A 76 76 0 0 1 176 100",
"text": "OFFICIAL · [color, #7A1F2E]STATE CORPORATION COMMISSION[/color]",
"alignment": "middle",
"style": "sealTopText"
}
}
Text wider than its path is never clipped. On a circular arc with alignment: middle — the seal-ring case — the whole string scales down uniformly to fit the arc; everywhere else the text continues past the path ends at its natural size. Both formats agree, and a render diagnostic reports the overflow either way. Size arcs generously all the same: a fitted legend reads best when the shrink is slight.
The arc can sit at any angle — d is free-form, so an arc spanning any portion of a circle places its text there (alignment: middle centers the string on the arc's midpoint). The horizontal-endpoint semicircles in the seal examples are a convention, not a constraint.
Content
Text
{ "text": { "x": 150, "y": 200, "text": "Section header", "style": "label" } }
When width is set, (x, y) is the top-left of a text box and the style's textAlign centers/right-aligns the text within that box. Without width, the anchor is the alignment pivot — center alignment pivots on (x, y), right alignment ends at it.
{ "text": { "x": 0, "y": 10, "width": 180, "text": "EDGE", "style": "laneHeader" } }
Vertical anchoring — baseline. By default y is the top of the text. Set baseline to change what y means vertically (it's an element field, beside x/y):
baseline | y is the… |
|---|---|
(omitted) / hanging / text-before-edge | top of the text |
middle / central | vertical center — centers the text on y |
alphabetic | baseline (SVG's own default) |
text-after-edge / ideographic | bottom of the text |
baseline: "middle" is the clean way to vertically center a label in a shape — write y at the box's mid-height instead of computing y = height/2 − fontSize/2. PDF places it exactly from font metrics; Word approximates via the text box's offset.
{ "text": { "x": 55, "y": 25, "baseline": "middle", "text": "42", "style": "gaugeValue" } }
Set fontFamily on the text style to use an embedded font, and switch fonts mid-string with the [font, Family] Shortcode — both text and textPath are shaped at render time (see Multi-script text and seals).
Image
{ "image": { "x": 50, "y": 30, "width": 100, "height": 40, "href": "images/logos/acme.png" } }
Barcode (extension)
Place any supported barcode symbology at exact coordinates — PDF417, DataMatrix, QR, Code128, Code39, MaxiCode, and the 2D specialty codes. There is no SVG equivalent: the encoder runs at render time and emits native vector, so the encoded value can be a $data.* reference.
{
"barcode": {
"x": 80, "y": 56,
"width": 40, "height": 40,
"spec": { "type": "datamatrix", "code": "$data.credential.payload" }
}
}
| Property | Type | Description |
|---|---|---|
x, y | number | Top-left of the barcode in local coordinates. |
width, height | number | Render dimensions in points. For square 2D codes, set both equal. Omit to use per-symbology defaults. |
spec.type | string | Symbology — datamatrix, qrcode, pdf417, code128, code39, aztec, maxicode, microqr, rmqr, micropdf417, dotcode, hanxin, code16k, codablockf, ultracode, gridmatrix, upnqr, and all 1D linear types. See Symbologies. |
spec.code | string | The payload to encode. Supports $data.* and $item.* references. |
This is the positioned barcode primitive — distinct from the [barcode, …] Shortcode which renders inline with text flow. Use this form when you need the barcode at a precise location alongside other elements (the center of a seal, a corner of a form, an edge sidebar).
Live examples — official-seal.json (PDF417 verification record next to control numbers), graduation-certificate.json and achievement-certificate.json (DataMatrix at the visual center of an academic seal), stock-certificate.json (DataMatrix verification badge), void-check.json (edge-mounted Code128 watermark).
Multi-script text and seals
text and textPath are shaped with the same engine that shapes flowing paragraphs — at render time. Arabic and Hebrew join into their contextual forms and set right-to-left, Devanagari builds conjuncts, Thai stacks vowel and tone marks, and Chinese/Japanese/Korean render from a CJK family. Choose the face with fontFamily on the text style, and switch fonts per run with the [font, Family] Shortcode. Each textPath ring can therefore carry a different script — which is what makes a multi-script seal possible.
Mixed-script text is zero-config: a line mixing Latin with Arabic, Hebrew, Indic or Thai splits into per-script slices, each routed to a covering font, and right-to-left segments — numbers included — order correctly with no declaration. Keep each textPath to a single script: text on a path shapes with one script's rules, so give each ring its own script, exactly as the seal examples do.
Live examples — world-languages-proclamation.json (one seal carrying Arabic, Latin, Greek and Devanagari on concentric textPath rings around a CJK character) and multilingual-device-guide.json (Latin + CJK outer rings, Devanagari + Thai inner rings around a bold CJK character). See Custom Fonts for the shaping and subsetting details.
SVG styles
SVG elements use a different property schema than paragraph styles. Use the keys below — color/backgroundColor/border are paragraph properties and will be silently ignored on drawing elements.
Naming aligns with SVG presentation attributes. Same semantics as SVG, JSON-style camelCase.
Each element resolves independently — like SVG. A shape takes its own
style; a shape with none inherits the enclosingg's style; with neither, it falls to the default (a thin black outline). Paint set on one child never leaks to a later sibling, so you don't need defensive resets likestrokeDasharray: [0]oropacity: 1— an element that doesn't declare a dash simply has none. To share appearance across siblings, put them in agwith a groupstyle.
| Property | Applies to | Description |
|---|---|---|
fill | shapes | Interior fill — a color, or a gradient object. |
stroke | shapes, lines, paths | Border / line / stroke color. |
strokeWidth | shapes, lines, paths | Stroke width in points. |
strokeDasharray | shapes, lines, paths | Dash pattern as number array: [on, off] for simple dash, [a, b, c, d, …] for dash-dot, [0.5, 2.5] paired with strokeLinecap: "round" for dotted. Omit for a solid line — dashes never leak between elements. |
strokeDashoffset | paths | Starting offset into the dash pattern (defaults to 0). |
strokeLinecap | shapes, lines, paths | butt (default) / round / square — line-end shape. Combined with strokeDasharray, round turns tiny on-segments into round dots instead of square pixels. |
strokeLinejoin | paths | miter (default) / round / bevel — corner join style at polyline vertices. |
strokeMiterlimit | paths | Positive float — controls how long a miter spike can extend before being chopped to a bevel. |
vectorEffect | shapes, lines, paths | non-scaling-stroke keeps the stroke width constant when the shape is inside a scaled symbol — a hairline stays a hairline no matter what size the use renders at, instead of thickening with the geometry. |
dropShadow | shapes, paths | Object { dx, dy, blur, color, opacity } — drop shadow behind the shape (dy positive drops it downward). Card lift, seal relief, badge depth. Only the painted parts cast a shadow, so an unfilled shape shadows its outline. Edge softness differs slightly between the two formats. |
opacity | all | 0.0–1.0 transparency, applied to fill and stroke. |
fillOpacity | shapes | 0.0–1.0 transparency of the fill only. Overrides opacity for the fill — a translucent fill under an opaque stroke (the standard highlight-box idiom). |
strokeOpacity | shapes, lines, paths | 0.0–1.0 transparency of the stroke only. Overrides opacity for the stroke. |
color | text, textPath | Text fill color. |
fontSize | text, textPath | Text size in points. |
fontWeight / fontStyle | text, textPath | Weight (bold, normal, 100…900) and style (italic, normal). |
fontFamily | text, textPath | Font family for embedded custom fonts. |
letterSpacing | text, textPath | Inter-character tracking in points (positive widens, negative tightens). |
textAlign | text | left / center / right — domain is the text's width when set, the anchor point otherwise. |
textRenderingMode | text, textPath | fill (default) / stroke / fillstroke / invisible / fillclip / strokeclip / fillstrokeclip / clip. |
skew | paths | [skewX] or [skewX, skewY] in degrees — applies a 2D skew transform. |
transform | paths | 6-element affine matrix [a, b, c, d, e, f] — raw ConcatMatrix. |
rotate | shapes | Rotation in degrees around the shape's center. |
{
"styles": {
"card": { "fill": "#1E40AF", "stroke": "#1E3A8A", "strokeWidth": 0.5 },
"cardLabel": { "fontSize": 9, "fontWeight": "bold", "color": "#FFFFFF", "textAlign": "center" },
"connector": { "stroke": "#16A34A", "strokeWidth": 1.5 }
}
}
Clickable shapes
Make a drawn shape a live link — a CTA button, a logo pointing at your site, a diagram node opening a reference — with link on the element (the flattened form of SVG's <a href> wrapper):
{ "rect": { "x": 0, "y": 8, "width": 160, "height": 42, "rx": 8, "style": "cta",
"link": "https://docpayload.com/docs" } }
link is available on rect, circle, ellipse, polygon, path, text, and image (where it complements href, the image source). The whole shape becomes the clickable region in both formats (for polygon/path, the shape's bounding box). Only absolute http, https, and mailto URLs are accepted — anything else is refused with a diagnostic and the shape renders without the link.
In a header or footer the shape still draws, but links there are not clickable in PDF. Put linked graphics in the body.
Clipping an image to a shape
Circular staff photos, shaped frames, cover portholes — set clip on the image element with inline geometry (same viewBox coordinates as the image):
{ "image": { "x": 150, "y": 0, "width": 120, "height": 120, "href": "images/photos/portrait.jpg",
"clip": { "circle": { "cx": 210, "cy": 60, "r": 58 } } } }
The clip shape is one of circle, ellipse, rect, or path (arbitrary outline via SVG path data), positioned in the same viewBox coordinates as the image itself. Draw a ring or frame after the clipped image to dress the rim. Both formats crop to the exact same outline; keep the clip within the image box.
Fit text to a fixed slot — textLength on the text element forces the rendered text to an exact width (viewBox units): a variable-length name always filling the same badge slot. lengthAdjust picks the mechanism: spacing (default — the gaps between glyphs stretch or squeeze) or spacingAndGlyphs (the glyphs scale too, for a condensed/expanded look). Single-line only — it is ignored with a diagnostic when the text contains [br].
{ "text": { "x": 4, "y": 15, "baseline": "middle", "text": "MAXIMILIENNE DE LONGCHAMP",
"style": "name", "textLength": 172, "lengthAdjust": "spacingAndGlyphs" } }
Aspect-ratio fitting — preserveAspectRatio on the image element controls how a photo meets a box of a different shape: meet letterboxes it (whole image visible, centered), slice covers the box (centered, overflow cropped). Omit it to stretch. Prefer an explicit meet/slice whenever the box and photo proportions differ — that is also the only mode guaranteed identical across both output formats.
Markers — arrowheads on lines and polylines
Every connector, callout and dimension line needs an arrowhead — declare it on the element instead of hand-computing polygons:
{ "line": { "x1": 100, "y1": 27, "x2": 218, "y2": 27,
"markerEnd": { "shape": "triangle", "size": 7 }, "style": "connector" } }
linetakesmarkerStart/markerEnd;polylineaddsmarkerMid(one marker per interior vertex — data-point dots on a trace).shapeistriangle(arrowhead, tip on the vertex),diamond, orcircle(centered on the vertex);sizeis the length/diameter inviewBoxunits (default 6).- The marker fills with the element's style
strokecolor — no separate style needed. markerStartpoints backward along the line, somarkerStart+markerEndon one line is a double-headed dimension arrow.
Both output formats draw identical heads. For a custom head beyond the built-in three, compose a reusable symbol.
Gradient fills
fill also accepts a gradient object — linear or radial — rendered as native vector shading in both formats:
{
"styles": {
"ribbon": { "fill": { "linearGradient": { "angle": 90, "stops": [
{ "offset": 0, "color": "#0F766E" },
{ "offset": 1, "color": "#134E4A" }
] } } },
"glow": { "fill": { "radialGradient": { "stops": [
{ "offset": 0, "color": "#FDE68A" },
{ "offset": 0.6, "color": "#F59E0B" },
{ "offset": 1, "color": "#B45309" }
] } } }
}
}
linearGradient—anglein degrees, clockwise from left→right:0runs →,90runs ↓,135runs ↙.stopsis an ordered list of{ offset, color }whereoffsetis a0–1fraction along the gradient andcolortakes the usual hex/name vocabulary. Two stops minimum; add more for multi-band ribbons.radialGradient— radiates from the shape's center (offset: 0) out to its corners (offset: 1). Samestopsform.
Gradients map to the shape's own bounding box, so one named style tints a rect, a circle, a path, or a polygon alike — and each shape in a group gets its own gradient extent. Combine freely with stroke (the outline stays a solid color) and fillOpacity. A gradient spanning several separate shapes as one wash isn't expressible — merge them into a single path, or give each shape its own gradient.
Data binding inside SVG
$data.* / $item.* references resolve inside an svg block in the value slots: text.text, textPath.text, image.href, and barcode.spec.code — including inside nested g groups. Geometry and style values are not data-bound; to make an instance's position or size dynamic, declare it as a symbol and pass x / y / width / height / rotate through use.params.
Symbols & reuse — use
Draw a graphic once, instantiate it many times. A symbol is a document whose content is a single SVG graphic; a use element stamps it into another graphic at a destination box, scaling it from the symbol's viewBox and binding per-instance data — exactly like SVG's <use>.
Declaring a symbol
A symbol is an ordinary document file with a metadata.name handle and an SVG payload. The name is what authors reference — it's independent of the file name and folder.
{
"component": {
"metadata": { "name": "quality-seal" },
"styles": {
"sealOuter": { "stroke": "#10243E", "strokeWidth": 2 },
"sealGrade": { "fontSize": 46, "fontWeight": "bold", "color": "#10243E", "textAlign": "center" }
},
"content": [
{
"svg": {
"viewBox": [150, 150],
"children": [
{ "circle": { "cx": 75, "cy": 75, "r": 72, "style": "sealOuter" } },
{ "text": { "x": 0, "y": 45, "width": 150, "text": "$data.grade", "style": "sealGrade" } }
]
}
}
]
}
}
$data.grade is a placeholder filled in per instance (see Data Binding). The symbol's named styles travel with it — they resolve in whatever document uses it.
Instantiating with use
Inside any SVG graphic, a use element names the symbol and gives a destination box. width/height scale the symbol from its viewBox; params supplies that instance's values.
{
"svg": {
"viewBox": [472, 175],
"children": [
{ "use": { "name": "quality-seal", "x": 16, "y": 12, "width": 150, "height": 150, "params": { "grade": "A" } } },
{ "use": { "name": "quality-seal", "x": 206, "y": 27, "width": 120, "height": 120, "params": { "grade": "B" } } },
{ "use": { "name": "quality-seal", "x": 372, "y": 39, "width": 100, "height": 100, "params": { "grade": "A+" } } }
]
}
}
One definition, three sizes, three grades — no duplicated geometry. The rings, text, and any nested shapes scale as a unit.
- Output
- Template
- Data
use field | Meaning |
|---|---|
name | The symbol's metadata.name (the handle authors write). |
id | Optional GUID pin; wins over name when both are present. |
x / y | Destination top-left, in the host graphic's coordinates. |
width / height | Destination size; the scale is derived against the symbol's viewBox. |
params | Per-instance values bound to the symbol's $data.* placeholders. May also carry x/y/width/height/rotate to make this use's own geometry dynamic (e.g. "params": { "width": "$data.columnWidth" } }) — a value here wins over the literal field of the same name. |
rotate / skew / transform | Optional transforms applied to the instance (degrees / degrees / 6-element matrix). |
style | Named style cascaded to the instance's shapes that declare none. |
Transforms compose in SVG order (translate → rotate → skew → scale, then the raw transform matrix). Symbols can use other symbols; nesting is depth-limited with a cycle guard.
DOCX note. In Word output a
usebecomes a nested group carrying translate, scale, and rotate. Skew and raw-matrix transforms aren't expressible on a Word group and are dropped (the PDF honors them in full), and a rotated group pivots on its center rather than its top-left.
Patterns gallery — paths, curves, and textPath
A second live example exercising the more decorative end of the API: SVG path data, quadratic and cubic Bezier curves, arcs, textPath (text flowed along a curve), polygon shapes, and overlapping compositions. Useful as a reference when authoring seals, ornamental borders, math/geometry illustrations, or anything where the layout language is "place these curves exactly here."
- Output
- Template
- Data
When something doesn't draw
Malformed path data, an unresolvable image, an undeclared font family, or text in a script no font covers all degrade politely: the element is skipped and the render continues. Opt into Rendering Diagnostics to see each failure named in-document, as a marker at the element that raised it and in the end-of-document appendix.
What's next
- Watermarks — page chrome behind the body: any content node, including full SVG graphics, repeated across pages.
- Tables — tabular layouts that flow with paragraphs.
- Columns — multi-column flow layouts.