Selling and buying / A4
Quotation HTML template with CSS
A priced proposal with a validity date, a scope, optional items kept out of the headline total, and somewhere to sign.
When this document is the right one
A prospect asks what it will cost. A quote is a legally meaningful offer in most jurisdictions once accepted, which is why the validity date and the assumptions are not decoration.
Why each part is there
The fields are visible in the markup. What is not visible is why they are present, which is the part that gets removed first when someone adapts a template for their own use.
- A validity date, set prominently. Without it the price is open indefinitely and material costs are not.
- A scope paragraph in prose, because a table of line items does not describe what is being bought.
- Optional items marked and excluded from the headline total, so nobody accepts a number that includes things they did not want.
- Numbered assumptions and exclusions, which is where the disputes come from and therefore where the effort belongs.
- A signature block, because a signed quote is the fastest path from proposal to purchase order.
The template
A complete file. Doctype, stylesheet, body: paste it into a renderer unchanged and it produces a finished A4 page. Replace the sample data and the styling holds.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Quotation Q-2026-0288</title>
<style>
@page { size: A4; margin: 18mm 16mm 22mm; }
* { box-sizing: border-box; }
body { margin: 0; font: 10pt/1.5 "Helvetica Neue", Arial, sans-serif; color: #16202b; }
header { display: flex; justify-content: space-between; align-items: flex-start; }
h1 { margin: 0; font-size: 24pt; letter-spacing: -0.02em; }
.valid { text-align: right; border: 1.5px solid #16202b; padding: 3mm 4mm; }
.valid .k { font-size: 7.5pt; text-transform: uppercase; letter-spacing: 0.08em;
color: #5b6b7c; }
.valid .v { font-size: 11pt; font-weight: 700; }
.meta { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6mm; margin: 8mm 0;
border-top: 1px solid #dbe2e8; border-bottom: 1px solid #dbe2e8;
padding: 5mm 0; font-size: 9pt; }
.meta .k { font-size: 7.5pt; text-transform: uppercase; letter-spacing: 0.06em;
color: #5b6b7c; margin-bottom: 1mm; }
address { font-style: normal; }
.scope { margin-bottom: 7mm; }
.scope h2 { font-size: 10pt; margin: 0 0 2mm; }
table { width: 100%; border-collapse: collapse; }
thead { display: table-header-group; }
th { text-align: left; font-size: 8pt; text-transform: uppercase; letter-spacing: 0.06em;
color: #5b6b7c; border-bottom: 1.5px solid #16202b; padding-bottom: 2mm; }
td { padding: 3mm 0; border-bottom: 1px solid #eef2f5; vertical-align: top; }
tr { break-inside: avoid; }
.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Optional lines are quoted but not counted. Mixing them into the total is
the most common way a quote is accepted for a number nobody agreed to. */
tr.optional td { color: #5b6b7c; }
tr.optional .tag { display: inline-block; border: 1px solid #b8c4cf; border-radius: 2mm;
padding: 0.3mm 1.6mm; font-size: 7pt; text-transform: uppercase;
letter-spacing: 0.06em; margin-left: 2mm; }
.totals { width: 82mm; margin: 6mm 0 0 auto; break-inside: avoid; }
.totals div { display: flex; justify-content: space-between; padding: 1.5mm 0; }
.totals .grand { border-top: 1.5px solid #16202b; margin-top: 2mm; padding-top: 2.5mm;
font-size: 13pt; font-weight: 700; }
.totals .opt { color: #5b6b7c; font-size: 9pt; }
.assumptions { margin-top: 10mm; break-inside: avoid; }
.assumptions h2 { font-size: 9pt; text-transform: uppercase; letter-spacing: 0.08em;
color: #5b6b7c; margin: 0 0 2mm; }
.assumptions ol { margin: 0; padding-left: 5mm; font-size: 9pt; }
.assumptions li { margin-bottom: 1.5mm; }
.accept { margin-top: 12mm; border-top: 1.5px solid #16202b; padding-top: 6mm;
display: grid; grid-template-columns: 1fr 1fr 40mm; gap: 8mm;
break-inside: avoid; }
.accept div { border-bottom: 1px solid #16202b; height: 15mm; position: relative; }
.accept span { position: absolute; bottom: -6mm; font-size: 8pt; color: #5b6b7c; }
</style>
</head>
<body>
<header>
<div>
<h1>Quotation</h1>
<div style="margin-top:2mm;font-size:11pt;font-weight:700">Kilnworks Studio</div>
</div>
<div class="valid">
<div class="k">Valid until</div>
<div class="v">30 June 2026</div>
</div>
</header>
<section class="meta">
<div>
<div class="k">Quotation number</div>Q-2026-0288
<div class="k" style="margin-top:3mm">Prepared</div>14 May 2026
</div>
<div>
<div class="k">Prepared for</div>
<address>Ravenshill Hotel Group<br>Attn: Dara Quinn<br>Bath BA1 2QP</address>
</div>
<div>
<div class="k">Prepared by</div>
<address>Kilnworks Studio<br>Ella Prentice<br>ella@kilnworks.example</address>
</div>
</section>
<section class="scope">
<h2>Scope</h2>
<p style="margin:0">
Design, glazing and firing of a bespoke tableware range for the Bath and Wells
properties: 220 covers, four piece setting, in the house glaze developed in the
sample round of March 2026. Delivery in two batches to allow a service trial
before the second firing.
</p>
</section>
<table>
<thead>
<tr><th>Item</th><th class="num">Qty</th><th class="num">Unit</th><th class="num">Amount</th></tr>
</thead>
<tbody>
<tr><td>Dinner plate, 27cm, house glaze</td><td class="num">220</td>
<td class="num">18.00</td><td class="num">3,960.00</td></tr>
<tr><td>Side plate, 19cm</td><td class="num">220</td>
<td class="num">12.50</td><td class="num">2,750.00</td></tr>
<tr><td>Bowl, 16cm</td><td class="num">220</td>
<td class="num">14.00</td><td class="num">3,080.00</td></tr>
<tr><td>Firing trial and glaze matching, second batch</td><td class="num">1</td>
<td class="num">450.00</td><td class="num">450.00</td></tr>
<tr class="optional">
<td>Hand-applied rim detail<span class="tag">Optional</span></td>
<td class="num">660</td><td class="num">2.20</td><td class="num">1,452.00</td>
</tr>
<tr class="optional">
<td>Replacement stock held for 12 months<span class="tag">Optional</span></td>
<td class="num">1</td><td class="num">890.00</td><td class="num">890.00</td>
</tr>
</tbody>
</table>
<div class="totals">
<div><span>Quoted subtotal</span><span>10,240.00</span></div>
<div><span>VAT at 20%</span><span>2,048.00</span></div>
<div class="grand"><span>Total quoted</span><span>GBP 12,288.00</span></div>
<div class="opt"><span>Optional items, if taken</span><span>+ 2,810.40 inc VAT</span></div>
</div>
<section class="assumptions">
<h2>Assumptions and exclusions</h2>
<ol>
<li>Quantities are as briefed on 06 May 2026. A change of more than 10% will be requoted.</li>
<li>Hand-thrown ware varies by up to 4% in dimension; this is a property of the process rather than a defect.</li>
<li>Lead time is fourteen weeks from a signed acceptance and a 40% deposit, and it is not held while a quote is under consideration.</li>
<li>Delivery to two addresses within the UK is included. Installation, styling and photography are not.</li>
<li>Clay and glaze materials are quoted at May 2026 cost and are the one line that may move before signature.</li>
</ol>
</section>
<div class="accept">
<div><span>Signed for Ravenshill Hotel Group</span></div>
<div><span>Name and position</span></div>
<div><span>Date</span></div>
</div>
</body>
</html>The layout decision worth understanding
Optional lines are styled differently and their subtotal is shown separately below the grand total rather than inside it. The temptation is to include everything in one impressive number, and the cost of that is an argument at invoice time about what was actually agreed.
The mistake people make adapting it
Reusing invoice numbering, or letting the quote become the invoice by changing the heading. A quote and an invoice have different sequences, different legal weight and different retention, and merging them loses all three distinctions.
Rendering it
The page box is declared in the template's own CSS as A4, so the size travels with the markup rather than living in the code that calls the renderer. A4 is also one of the six named formats the API accepts, so it can be passed in the request options instead if that suits your setup better.
curl -X POST https://api.pdfpipe.xyz/v1/pdf \
-H "Authorization: Bearer $PDFPIPE_KEY" \
-H "Content-Type: application/json" \
-d '{
"html": "<!doctype html>...",
"options": { "format": "A4" }
}' \
--output quote.pdfFrequently asked
Can I use this template commercially?
Yes. Copy it, change it, ship it. It is sample markup written to be taken, and the sample data in it is invented, so replace the names and the numbers before anyone sees it.
Why is the page size in the CSS rather than in the API call?
Because a quotation is a A4 document, and that is a property of the document rather than of the code that renders it. Declaring it in the page box means the size cannot be lost between the template and the call, which is the usual way a document ends up on the wrong paper.
Will it look the same in every renderer?
The layout will, because it uses ordinary CSS. The page break behaviour will not: break-inside and break-after are implemented differently by browser engines and by dedicated print engines, and some of the paged media specification is not implemented in browser renders at all. That difference is documented per property in the paged CSS reference.
Other templates
Documents from the same part of a business, and one from each of the other groups.
Purchase order HTML template
Issued by the buyer: an instruction to supply specific goods at specific prices, with separate delivery and invoicing addresses and the conditions of the order.
Trade price list PDF template
A dated catalogue of prices by item code, usually with a second column for volume, issued to trade accounts.
Order confirmation HTML template
Sent to the buyer after an order is placed: what was ordered, what it cost, and above all when it will arrive.
Product datasheet PDF template
A two-column technical specification sheet with a revision number, grouped tables, a dimensions figure and an ordering code.
HTML invoice template with CSS
The standard commercial invoice: a demand for payment with line items, a tax figure, and terms that say when the money is due.
Payment receipt HTML template
Proof that a payment was made: the amount, the payment reference, the method, and what it was for.
Packing slip HTML template
The document that goes in the box: what was ordered, what was actually shipped, and no prices at all.
Every template
The full set, grouped by what part of a business produces the document.
A4 page size for PDF generation
A4 is the default page for business documents everywhere except North America, and the default this API uses when no format is given.
Paste the template into the playground and get the PDF back. No signup, no key.