Template Components

Card

The Card node in VaultPDF. Renders a structured key-value block with configurable variants, border styles, label layouts, and field definitions. Ideal for contact details, order summaries, address blocks, and grouped metadata.

Overview

A Card (card) is a self-contained block that displays a set of labelled fields as a structured table. Unlike a section (which lays out child nodes vertically), a card owns its field definitions directly through a fields array, making it more portable and easier to compose inside layout groups.

Four variants give the card different visual treatments:

VariantBest used for
defaultGeneral key-value information (customer details, order metadata)
summaryTotals and KPI callouts - each field becomes a mini labeled tile
addressPostal or delivery addresses - values stacked as a single text block, no labels
groupedNested payload objects - renders child cards recursively

Title & Header

PropertyTypeDefaultDescription
titlestring-Card heading. Supports {{FIELDNAME}} tokens.
subtitlestring-Optional secondary line rendered beneath the title in a smaller muted font.
titleIconstring-Decorative icon key placed next to the title (e.g. "star", "package", "list").
accentColorcolortheme.primaryColor applied to the title text, icon accent pipe, and -- when showHeader is off -- the inline title.
showHeaderbooleantrueWhen true, renders a filled header bar (same style as a section header). When false, the title is rendered inline as an accent-colored heading inside the card body.
headerFillColorcolortheme.primaryBackground color of the header bar. Only relevant when showHeader is true.
headerBorderBottomnumber0Width (pt) of the border line drawn below the header bar.

Title-less cards

Set showHeader: false and omit title entirely to produce a title-less card - useful for compact summary tiles inside a layout group where the section already provides a heading.


Data Binding

PropertyTypeDefaultDescription
dataPathstring-Dot-path into the JSON payload used to scope field-name suggestions in the Designer. Example: "customer" makes the Designer suggest fields from payload.customer.

All field value expressions resolve against the full JSON payload root - dataPath does not restrict which payload fields can be referenced. Setting dataPath tells the Designer which object in your payload to use when suggesting field names, but you can reference any payload path in a value string regardless.


Variant

PropertyTypeDefaultDescription
variant"default" | "summary" | "address" | "grouped""default"Controls the visual treatment of the card body. See Variant Details below.

Field Layout

PropertyTypeDefaultDescription
labelPosition"left" | "top""left""left" - label and value sit side-by-side in a two-column row. "top" - label renders above the value in a single column.
labelWidthnumber110Width (pt) of the label column when labelPosition is "left". Ignored for "top" layout.
valueAlign"left" | "right" | "center""left"Horizontal alignment of value text within its cell.
columns1 | 2 | 31Splits the fields array into N side-by-side columns inside the card body.
fieldGapnumber4Gap (pt) between internal field columns. Also used as the row spacing between mini-tiles in summary variant.
labelBoldbooleanfalseApply bold to all label cells.
valueBoldbooleanfalseApply bold to all value cells.
valueAllCapsbooleanfalseUppercase all value text. Static values are transformed at build time; {{token}} values are flagged for runtime transformation.
emphasizeLastRowbooleanfalseRenders the last field row with bold text and a slightly larger font size -- useful for "Total" rows in a summary card.
showDividerbooleansame as emphasizeLastRowDraws a horizontal separator line immediately above the last field row when there are two or more fields. Set explicitly to override the default.

Border & Background

PropertyTypeDefaultDescription
borderStyle"full" | "minimal" | "none""full" ("minimal" for address variant)Outer card border. "full" -- full rectangle on all 4 sides. "minimal" -- bottom line only. "none" -- no outer border.
borderColorcolortheme.borderColorColor of the outer card border.
innerBorderStyle"full" | "minimal" | "none""minimal"Divider lines between field rows. "full" -- full-width row separators. "minimal" -- bottom-only line on each row. "none" -- no row dividers.
innerBorderColorcolortheme.borderColorColor of the inner row dividers.
backgroundColorcolor(transparent)Card body fill color. Useful for highlighted summary blocks.
radiusnumber0Corner radius (pt) applied to the outer card border. Range: 0--16.

Spacing

PropertyTypeDefaultDescription
paddingnumber12Inner padding (pt) applied to the card content area. Range: 0--30.
marginTopnumber0Space (pt) above the card block. Range: 0--60.
marginBottomnumber0Space (pt) below the card block. Range: 0--60.
widthnumber | "star""star"Explicit card width in pt, or "star" to fill available space. Useful when placing a narrow summary card on the right side of a layout group.

Variant Details

Default

The standard label-value block. Each field renders as a two-column row (label left, value right) or a single stacked column when labelPosition: "top". Rows are separated by innerBorderStyle lines.

{
  "type": "card",
  "props": {
    "title": "Customer",
    "variant": "default",
    "showHeader": true,
    "labelPosition": "left",
    "labelWidth": 110,
    "valueAlign": "left",
    "borderStyle": "full",
    "innerBorderStyle": "minimal",
    "fields": [
      { "key": "name",    "label": "Name",    "value": "{{customer.name}}" },
      { "key": "email",   "label": "Email",   "value": "{{customer.email}}" },
      { "key": "phone",   "label": "Phone",   "value": "{{customer.phone}}" }
    ]
  }
}

Summary

Each field becomes a mini tile - a small table cell with the label displayed in a filled header bar (accentColor background, contrast text) and the value centered below. Tiles are arranged in rows of up to columns tiles each (defaults to 1 if columns is unset, or fills up to 4 tiles per row automatically when columns: 0).

Use emphasizeLastRow: true and showDivider: true to visually separate a total row from sub-totals.

{
  "type": "card",
  "props": {
    "title": "Order Totals",
    "titleIcon": "star",
    "variant": "summary",
    "showHeader": false,
    "columns": 1,
    "valueAlign": "right",
    "emphasizeLastRow": true,
    "showDivider": true,
    "fields": [
      { "key": "subtotal", "label": "Subtotal",  "value": "{{subtotal}}",  "format": "currency" },
      { "key": "tax",      "label": "GST (10%)", "value": "{{tax}}",       "format": "currency" },
      { "key": "total",    "label": "Total",     "value": "{{total}}",     "format": "currency" }
    ]
  }
}

Address

Values are rendered as a single multiline text block - one line per field, labels omitted. Ideal for postal addresses, delivery notes, or any block where the formatting itself conveys structure.

The outer borderStyle defaults to "minimal" for this variant (bottom-line only). Set borderStyle: "none" for a borderless address block.

{
  "type": "card",
  "props": {
    "title": "Deliver To",
    "variant": "address",
    "showHeader": false,
    "borderStyle": "none",
    "fields": [
      { "key": "line_0", "label": "Name",           "value": "{{deliveryName}}" },
      { "key": "line_1", "label": "Street",         "value": "{{deliveryStreet}}" },
      { "key": "line_2", "label": "City/State/Zip", "value": "{{deliveryCity}}, {{deliveryState}} {{deliveryPostcode}}" }
    ]
  }
}

Grouped

Renders a nested payload object as a stack of sub-cards. Instead of a flat fields array, a grouped card holds a children array - each child is typically a default or address card. Use this variant when your payload contains nested objects (for example, a shipTo object that itself contains a contact sub-object) and you want each level to appear as a distinct, titled card block.


Fields

The fields array defines the rendered rows (or tiles, for summary). Fields are rendered in declaration order.

Field Properties

PropertyTypeRequiredDescription
keystringYesUnique identifier for the field within this card.
labelstringYesDisplay label. Shown as-is in default variant; used as tile heading in summary. Omitted in address.
valuestringYesValue text. Supports {{fieldName}} and {{fieldName|format}} tokens.
formatstringNoFormat hint applied to {{token}} values. See Field Formats.
hiddenbooleanNoWhen true, the field is omitted from the rendered output. Useful for toggling fields without removing them from the schema.
styleobjectNoPer-field style overrides: { fontSize, color }.
span"full"NoForce the field to render at full card width, below the multi-column field layout. Useful for long text or signature-style lines.

Field Formats

ValueEffect
textPlain string -- no transformation (default).
numberNumeric with locale-aware thousands separator.
currencyLocale-formatted currency value (e.g. $1,234.56).
dateShort date string (e.g. 31/03/2026).
datetimeDate and time (e.g. 31/03/2026 14:22).
booleanRenders true/false as Yes/No.
percentageAppends % and formats as a number.

Formats can also be embedded inline in the value string using the pipe syntax: "{{amount|currency}}".

Connecting tokens to your payload

{{FIELDNAME}} tokens are resolved against the full JSON payload at render time. Use dot-notation for nested fields: {{order.customer.name}} reads payload.order.customer.name. Field names containing dots or spaces are also supported using the greedy longest-match resolver - for example {{Header.No.}} resolves the literal key "No." on Header.


Visibility

PropertyTypeDefaultDescription
hiddenbooleanfalseHides the entire card. Equivalent to visible: false on section nodes.

Examples

Info card -- two columns, top label

{
  "type": "card",
  "props": {
    "title": "Order Details",
    "titleIcon": "package",
    "variant": "default",
    "showHeader": true,
    "labelPosition": "top",
    "columns": 2,
    "fieldGap": 4,
    "borderStyle": "full",
    "innerBorderStyle": "none",
    "padding": 10,
    "fields": [
      { "key": "orderId",    "label": "Order Number", "value": "{{orderId}}" },
      { "key": "orderDate",  "label": "Date",         "value": "{{orderDate}}",  "format": "date" },
      { "key": "reference",  "label": "Reference",    "value": "{{reference}}" },
      { "key": "dueDate",    "label": "Due Date",     "value": "{{dueDate}}",    "format": "date" }
    ]
  }
}

Summary card -- totals block on the right

Pair this card with a table on the left inside a layout_group:

{
  "type": "card",
  "props": {
    "title": "Invoice Totals",
    "variant": "summary",
    "showHeader": false,
    "accentColor": "theme.primary",
    "columns": 1,
    "valueAlign": "right",
    "labelBold": true,
    "emphasizeLastRow": true,
    "showDivider": true,
    "borderStyle": "full",
    "innerBorderStyle": "full",
    "padding": 10,
    "fields": [
      { "key": "subtotal", "label": "Subtotal",   "value": "{{subtotal}}",   "format": "currency" },
      { "key": "discount", "label": "Discount",   "value": "{{discount}}",   "format": "currency" },
      { "key": "tax",      "label": "GST (10%)",  "value": "{{tax}}",        "format": "currency" },
      { "key": "total",    "label": "Total Due",  "value": "{{totalDue}}",   "format": "currency" }
    ]
  }
}

Address card -- borderless

{
  "type": "card",
  "props": {
    "title": "Ship To",
    "variant": "address",
    "showHeader": false,
    "borderStyle": "none",
    "accentColor": "theme.primary",
    "padding": 0,
    "fields": [
      { "key": "company", "label": "Company", "value": "{{shipTo.company}}" },
      { "key": "street",  "label": "Street",  "value": "{{shipTo.street}}" },
      { "key": "suburb",  "label": "City",    "value": "{{shipTo.city}}, {{shipTo.state}}  {{shipTo.postcode}}" },
      { "key": "country", "label": "Country", "value": "{{shipTo.country}}" }
    ]
  }
}

Placing Cards in Layout Groups

Cards placed inside a layout_group respect the column width computed by the group. Use width to pin a card to a fixed pt size (e.g. a narrow totals card on the right):

{
  "type": "layout_group",
  "props": { "columns": [{ "width": "star" }, { "width": 30 }], "columnGap": 12 },
  "children": [
    { "type": "table", "props": { "...": "..." } },
    {
      "type": "card",
      "props": {
        "variant": "summary",
        "width": 160
      }
    }
  ]
}

Equal-height borders in layout groups

When a card is placed inside a layout_group, its borderStyle is promoted to the cell level so all cells in the same row share equal-height borders. Cards and sections placed side-by-side will automatically align their border lines.


  • Section - child-node-based layout block; use cards when you want self-contained field ownership
  • Layout Group - multi-column container for placing cards side-by-side
  • Table - for array-backed tabular data
  • Template Settings - theme tokens referenced by accentColor, borderColor, and headerFillColor

On this page