Business letter
A letter with inline rich text: bold, italic, monospace and clickable links on the same line.
Paragraphs use spans to mix weights and colours within one wrapped flow, and a link span becomes a real link annotation in the PDF.
Rich text spans
Links
1 page
render_letter.rb
ruby
require 'json'
require 'soli/pdf'
template = JSON.parse(File.read('letter.template.json'))
data = JSON.parse(File.read('letter.data.json'))
pdf = Soli::PDF.render(
template: template,
data: data,
title: 'Letter to Maison Lumière'
)
File.binwrite('letter.pdf', pdf)
Run it yourself
- Add the gem to your Gemfile — see Installation.
- Download letter.template.json and letter.data.json.
- Run
ruby render_letter.rb.
letter.template.json
json
{
"fonts": ["titillium"],
"footer": [
{ "type": "paragraph", "value": "${company.name} — ${company.email}", "options": { "alignment": "center", "fontSize": 8 } }
],
"content": [
{ "type": "paragraph", "value": "${company.name}", "options": { "fontSize": 22, "fontWeight": "bold" } },
{ "type": "paragraph", "value": "${company.tagline}", "options": { "fontSize": 11 } },
{ "type": "move", "y": 8 },
{ "type": "paragraph", "value": "${letter.place_date}", "options": { "alignment": "right", "fontSize": 10 } },
{ "type": "move", "y": 18 },
{ "type": "paragraph", "value": "${letter.greeting}", "options": { "fontSize": 11 } },
{ "type": "move", "y": 10 },
{ "type": "paragraph", "value": "${letter.body1}", "options": { "fontSize": 11 } },
{ "type": "move", "y": 8 },
{ "type": "paragraph", "value": "${letter.body2}", "options": { "fontSize": 11 } },
{ "type": "move", "y": 10 },
{ "type": "paragraph", "options": { "fontSize": 11 }, "spans": [
{ "text": "P.S. Inline rich text — run " },
{ "text": "soli serve .", "mono": true },
{ "text": " to preview, read the " },
{ "text": "style guide", "italic": true },
{ "text": " for the " },
{ "text": "details", "fontWeight": "bold" },
{ "text": ", or visit " },
{ "text": "our docs", "link": "https://soli.example/docs", "color": "1D4ED8" },
{ "text": "." }
] },
{ "type": "move", "y": 16 },
{ "type": "paragraph", "value": "${letter.closing}", "options": { "fontSize": 11 } },
{ "type": "move", "y": 6 },
{ "type": "paragraph", "value": "${letter.signature}", "options": { "fontSize": 11, "fontWeight": "bold" } }
]
}
letter.data.json
json
{
"data": {
"company": {
"name": "Atelier Nord",
"tagline": "Design & fabrication studio",
"email": "studio@ateliernord.fr"
},
"letter": {
"place_date": "Paris · 28 November 2025",
"greeting": "Dear Maison Lumière,",
"body1": "Thank you for trusting us with the rebranding of your flagship boutique. We have completed the identity system and the six signage panels, and scheduled installation for the week of 15 December as agreed.",
"body2": "The final invoice (AN-2025-0042) is attached separately. Please don't hesitate to reach out if anything needs adjusting before installation day — we'd rather get it right than get it fast.",
"closing": "Warm regards,",
"signature": "Camille Mercier — Atelier Nord"
}
}
}
More in Business documents