PDFPipe

Events, hospitality and membership / A5 landscape

Event ticket HTML template with stub

A landscape ticket with a tear-off stub, a scannable code sized in absolute units, and terms that a gate can actually enforce.

When this document is the right one

Admission is sold and has to work at a door with no signal, on a phone that may be offline or on paper. Anything requiring a live request fails at exactly the wrong moment, which is why the ticket is a file rather than a page.

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.

  • The code, which is the ticket. Everything else on the page is decoration that helps a human, and the code is what the scanner reads.
  • A perforation line between the ticket and the stub, drawn as a dashed border so it is obvious where to tear.
  • The stub carrying the code, the date and the admission count, since the stub is what the venue keeps.
  • The event date and time including a doors time, because those are different and the difference causes queues.
  • Terms that a gate can enforce, such as whether the ticket is transferable, rather than terms that only a lawyer could apply.

The template

A complete file. Doctype, stylesheet, body: paste it into a renderer unchanged and it produces a finished A5 landscape page. Replace the sample data and the styling holds.

html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Ticket, Kilnworks Open Studio</title>
<style>
  /* Ticket plus tear-off stub across a landscape A5. The perforation is the
     one line on this document that has to be in the right place. */
  @page { size: A5 landscape; margin: 0; }
  * { box-sizing: border-box; }
  body { margin: 0; height: 148mm; display: flex;
         font: 9pt/1.4 "Helvetica Neue", Arial, sans-serif; color: #101820;
         background: #fff; print-color-adjust: exact; -webkit-print-color-adjust: exact; }

  .main { flex: 1; padding: 11mm 12mm; display: flex; flex-direction: column; }
  .stub { width: 52mm; border-left: 2px dashed #101820; padding: 11mm 8mm;
          display: flex; flex-direction: column; background: #f4f1ea; }

  .brand { font-size: 9pt; letter-spacing: 0.2em; text-transform: uppercase; color: #6b6f76; }
  h1 { margin: 3mm 0 0; font-size: 22pt; line-height: 1.1; letter-spacing: -0.01em; }
  .when { margin-top: 5mm; font-size: 12pt; font-weight: 700; }
  .where { color: #4a5058; }

  dl { display: grid; grid-template-columns: auto 1fr; gap: 1.6mm 5mm; margin: 6mm 0 0;
       font-size: 9pt; }
  dt { color: #6b6f76; }
  dd { margin: 0; font-variant-numeric: tabular-nums; }

  .terms { margin-top: auto; font-size: 7.5pt; color: #6b6f76; line-height: 1.4; }

  /* The scannable code is the ticket. Everything else is decoration, so it is
     given absolute dimensions and a quiet zone rather than a percentage width. */
  .code { width: 34mm; height: 34mm; margin: 0 auto; padding: 2mm; background: #fff; }
  .code img { width: 100%; height: 100%; display: block; }
  .code-caption { text-align: center; font-size: 7.5pt; color: #6b6f76; margin-top: 2mm;
                  font-variant-numeric: tabular-nums; letter-spacing: 0.04em; }

  .stub .label { font-size: 7pt; text-transform: uppercase; letter-spacing: 0.09em;
                 color: #6b6f76; margin-top: 4mm; }
  .stub .value { font-weight: 700; }
  .stub .footer { margin-top: auto; font-size: 7pt; color: #6b6f76; }
</style>
</head>
<body>
  <div class="main">
    <div class="brand">Kilnworks Studio</div>
    <h1>Open Studio<br>and Kiln Opening</h1>
    <div class="when">Saturday 20 June 2026, 14:00</div>
    <div class="where">Unit 9, Riverside Works, Bath BA2 3EU. Doors 13:30.</div>

    <dl>
      <dt>Ticket holder</dt><dd>Helen Ashworth</dd>
      <dt>Ticket type</dt><dd>General admission, includes kiln opening</dd>
      <dt>Order</dt><dd>ORD-99031</dd>
      <dt>Ticket</dt><dd>TKT-2026-0442</dd>
    </dl>

    <p class="terms">
      Admits one. This ticket is non-transferable and the name above will be checked
      against photo identification at the door. The kiln opening runs at 15:30 and
      cannot be delayed for late arrivals. In the event of a firing being rescheduled
      you will be offered the next date or a full refund. Children under 12 free but
      must be accompanied. No refunds within 48 hours of the event.
    </p>
  </div>

  <div class="stub">
    <div class="code">
      <img src="data:image/png;base64,iVBORw0KGgo=" alt="Ticket QR code">
    </div>
    <div class="code-caption">TKT-2026-0442</div>

    <div class="label">Date</div><div class="value">20 Jun 2026</div>
    <div class="label">Time</div><div class="value">14:00</div>
    <div class="label">Admits</div><div class="value">1</div>

    <div class="footer">Retain this stub<br>kilnworks.example/open</div>
  </div>
</body>
</html>

The layout decision worth understanding

The code is given an absolute width and height with padding as a quiet zone, not a percentage. A code sized as a percentage of a flex container comes out a fraction wider than it is tall when the caption wraps, and a code that is not square is a code that does not scan.

The mistake people make adapting it

Printing the code on a tinted background to match the design. Scanners need contrast between the code and its surround, and a code on a pale colour reads fine on screen and fails under a scanner at a door in daylight.

Rendering it

The page box is declared in the template's own CSS as A5, so the size travels with the markup rather than living in the code that calls the renderer. A5 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.

bash
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": "A5" }
  }' \
  --output ticket.pdf

Frequently 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 event ticket is a A5 landscape 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.

Paste the template into the playground and get the PDF back. No signup, no key.