Conditional content
An order confirmation whose blocks appear or not depending on the data: if, unless and repeat.
Back-ordered items get a note, a balance line only shows when something is due, and the item list is a repeat rather than a table.
if / unless
repeat
1 page
render_dynamic.rb
ruby
require 'json'
require 'soli/pdf'
template = JSON.parse(File.read('dynamic.template.json'))
data = JSON.parse(File.read('dynamic.data.json'))
pdf = Soli::PDF.render(
template: template,
data: data,
title: 'Order SO-4821'
)
File.binwrite('dynamic.pdf', pdf)
Run it yourself
- Add the gem to your Gemfile — see Installation.
- Download dynamic.template.json and dynamic.data.json.
- Run
ruby render_dynamic.rb.
dynamic.template.json
json
{
"fonts": ["TitilliumWeb"],
"options": { "margins": 48 },
"content": [
{ "type": "image", "width": 36,
"value": "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='36' height='36'><rect width='36' height='36' rx='9' fill='#0f766e'/><circle cx='18' cy='18' r='9' fill='none' stroke='white' stroke-width='3'/></svg>" },
{ "type": "move", "x": 46, "y": 2 },
{ "type": "paragraph", "spans": [ { "text": "Helios Coffee", "color": "0f172a", "fontWeight": "bold" } ], "options": { "fontSize": 15 } },
{ "type": "paragraph", "spans": [ { "text": "ORDER CONFIRMATION", "color": "0f766e", "fontWeight": "bold" } ], "options": { "fontSize": 9 } },
{ "type": "move", "x": -46, "y": 18 },
{ "type": "paragraph", "spans": [ { "text": "Order ${order.id}", "color": "0f172a", "fontWeight": "bold" } ], "options": { "fontSize": 20 } },
{ "type": "paragraph", "spans": [ { "text": "${order.customer} · ${order.date}", "color": "64748b" } ], "options": { "fontSize": 11 } },
{ "type": "move", "y": 12 },
{ "type": "if", "when": "order.paid", "equals": "true",
"content": [ { "type": "paragraph", "spans": [ { "text": "PAID IN FULL", "color": "0f766e", "fontWeight": "bold" } ], "options": { "fontSize": 13 } } ],
"else": [ { "type": "paragraph", "spans": [ { "text": "BALANCE DUE — ${order.balance}", "color": "ef4444", "fontWeight": "bold" } ], "options": { "fontSize": 13 } } ] },
{ "type": "move", "y": 12 },
{ "type": "paragraph", "value": "Items", "options": { "fontSize": 14, "fontWeight": "bold" } },
{ "type": "move", "y": 4 },
{ "type": "repeat", "data": "items", "content": [
{ "type": "paragraph", "spans": [
{ "text": "${qty} × ", "color": "64748b" },
{ "text": "${name}", "fontWeight": "bold" },
{ "text": " ${price}" }
], "options": { "fontSize": 12 } },
{ "type": "unless", "when": "in_stock", "content": [
{ "type": "paragraph", "spans": [ { "text": " backordered — ships in ${eta}", "color": "f59e0b" } ], "options": { "fontSize": 10 } }
] },
{ "type": "move", "y": 3 },
{ "type": "hr", "color": "e2e8f0" },
{ "type": "move", "y": 7 }
] },
{ "type": "move", "y": 6 },
{ "type": "paragraph", "spans": [ { "text": "Subtotal ${order.subtotal}", "color": "64748b" } ], "options": { "fontSize": 11, "alignment": "right" } },
{ "type": "paragraph", "spans": [ { "text": "Shipping ${order.shipping}", "color": "64748b" } ], "options": { "fontSize": 11, "alignment": "right" } },
{ "type": "move", "y": 3 },
{ "type": "paragraph", "spans": [ { "text": "Total ${order.total}", "color": "0f172a", "fontWeight": "bold" } ], "options": { "fontSize": 14, "alignment": "right" } },
{ "type": "move", "y": 18 },
{ "type": "if", "when": "order.paid", "equals": "true",
"content": [ { "type": "paragraph", "spans": [ { "text": "Thank you for your business.", "color": "64748b" } ], "options": { "fontSize": 10 } } ],
"else": [ { "type": "paragraph", "spans": [ { "text": "Payment due within 14 days of delivery. · hello@helios.coffee", "color": "64748b" } ], "options": { "fontSize": 10 } } ] }
]
}
dynamic.data.json
json
{
"order": {
"id": "SO-4821",
"customer": "Café Lumière · Lyon",
"date": "30 June 2026",
"paid": false,
"balance": "€84.00",
"subtotal": "€131.00",
"shipping": "€8.00",
"total": "€139.00"
},
"items": [
{ "qty": 3, "name": "Ethiopia Yirgacheffe (1 kg)", "price": "€69.00", "in_stock": true },
{ "qty": 2, "name": "Colombia Huila (1 kg)", "price": "€44.00", "in_stock": false, "eta": "5 days" },
{ "qty": 1, "name": "Cold brew concentrate", "price": "€18.00", "in_stock": true },
{ "qty": 4, "name": "Unbleached filter papers", "price": "€8.00", "in_stock": true }
]
}
More in Showcase