PDFPipe

Events, hospitality and membership / A4

Travel itinerary PDF template

A day-by-day schedule with times, references in a monospace face, and every booking reference repeated in one block at the end.

When this document is the right one

A trip with more than two moving parts. The document is carried, and it is consulted at exactly the moments when a phone has no signal, no data or no battery.

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.

  • One block per day, each of which never splits across a page, because a traveller reads one day at a time.
  • Times in the left column, since the question is always what happens next rather than what happens in general.
  • Booking references in a monospace face with letter spacing, because they will be read aloud to a desk agent and O and 0 have to be distinguishable.
  • A single references block at the end repeating everything, so a lost bag or a missed connection needs one page rather than a search.
  • An instruction to print it, which is the point: an itinerary that only exists in an app fails at the airport where roaming does not work.

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.

html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Itinerary, Lisbon, 12 to 15 June 2026</title>
<style>
  @page { size: A4; margin: 18mm 16mm 20mm; }
  * { box-sizing: border-box; }
  body { margin: 0; font: 9.5pt/1.45 "Helvetica Neue", Arial, sans-serif; color: #16202b; }

  header { display: flex; justify-content: space-between; align-items: flex-start;
           border-bottom: 2px solid #16202b; padding-bottom: 5mm; }
  h1 { margin: 0; font-size: 18pt; }
  .ref { text-align: right; font-size: 8.5pt; color: #5b6b7c; }

  /* One block per day, and a day never splits across a page. A traveller
     holding this at an airport reads one day at a time. */
  .day { margin-top: 7mm; break-inside: avoid; }
  .day h2 { font-size: 11pt; margin: 0 0 2mm; padding-bottom: 1.5mm;
            border-bottom: 1.5px solid #16202b; }
  .day h2 span { color: #5b6b7c; font-weight: 400; font-size: 9pt; }

  .leg { display: grid; grid-template-columns: 18mm 1fr; gap: 2mm 4mm;
         padding: 2.5mm 0; border-bottom: 1px solid #eef2f5; }
  .leg .t { font-weight: 700; font-variant-numeric: tabular-nums; }
  .leg .what strong { display: block; }
  .leg .what small { color: #5b6b7c; display: block; margin-top: 0.6mm; }
  .leg .ref-code { font-family: "IBM Plex Mono", "Courier New", monospace;
                   letter-spacing: 0.06em; }

  .refs { margin-top: 8mm; border: 1px solid #dbe2e8; padding: 4mm; break-inside: avoid; }
  .refs h2 { margin: 0 0 2mm; font-size: 8pt; text-transform: uppercase;
             letter-spacing: 0.08em; color: #5b6b7c; }
  .refs table { width: 100%; border-collapse: collapse; font-size: 8.5pt; }
  .refs td { padding: 1.4mm 0; border-bottom: 1px solid #eef2f5; }
  .refs td:first-child { color: #5b6b7c; width: 40mm; }

  .warn { margin-top: 6mm; border-left: 3px solid #b3261e; padding: 2mm 0 2mm 5mm;
          font-size: 8.5pt; break-inside: avoid; }
</style>
</head>
<body>
  <header>
    <div>
      <h1>Lisbon, 12 to 15 June 2026</h1>
      <div style="margin-top:1.5mm;color:#5b6b7c">E. Prentice &middot; Kilnworks Studio</div>
    </div>
    <div class="ref">
      Itinerary ITN-2026-0119<br>
      Issued 20 May 2026<br>
      Booked by A. Boland
    </div>
  </header>

  <section class="day">
    <h2>Friday 12 June <span>Bath to Lisbon</span></h2>
    <div class="leg"><div class="t">05:45</div>
      <div class="what"><strong>Train, Bath Spa to Bristol Airport coach</strong>
        <small>Coach A4 from Bath bus station. Journey 55 minutes. Ticket in the wallet.</small></div></div>
    <div class="leg"><div class="t">08:35</div>
      <div class="what"><strong>Flight TP1235, Bristol to Lisbon</strong>
        <small>Arrives 11:20 local, which is the same clock time as Bristol in June.
        Booking reference <span class="ref-code">QK4M2X</span>. Hold bag included.</small></div></div>
    <div class="leg"><div class="t">12:30</div>
      <div class="what"><strong>Metro to Baixa-Chiado</strong>
        <small>Red line to Alameda, green line to Baixa-Chiado. About 35 minutes.</small></div></div>
    <div class="leg"><div class="t">14:00</div>
      <div class="what"><strong>Check in, Hotel Alecrim</strong>
        <small>Rua do Alecrim 88. Confirmation <span class="ref-code">HTL-88213</span>.
        Early check-in requested, not guaranteed.</small></div></div>
  </section>

  <section class="day">
    <h2>Saturday 13 June <span>Supplier visits</span></h2>
    <div class="leg"><div class="t">09:30</div>
      <div class="what"><strong>Sagres Comercio, Rua do Alecrim 88</strong>
        <small>Ana Ferreira. Ten minutes on foot from the hotel.</small></div></div>
    <div class="leg"><div class="t">13:00</div>
      <div class="what"><strong>Lunch, then train to Sintra</strong>
        <small>From Rossio, every 30 minutes, 40 minute journey.</small></div></div>
    <div class="leg"><div class="t">15:30</div>
      <div class="what"><strong>Ceramica Sintrense, kiln tour</strong>
        <small>Manuel Costa. Last train back at 21:12.</small></div></div>
  </section>

  <section class="day">
    <h2>Monday 15 June <span>Lisbon to Bath</span></h2>
    <div class="leg"><div class="t">10:00</div>
      <div class="what"><strong>Check out</strong><small>Luggage can be left until 16:00.</small></div></div>
    <div class="leg"><div class="t">17:55</div>
      <div class="what"><strong>Flight TP1234, Lisbon to Bristol</strong>
        <small>Arrives 20:40. Booking reference <span class="ref-code">QK4M2X</span>.
        Airport gates close 20 minutes before departure.</small></div></div>
  </section>

  <section class="refs">
    <h2>References in one place</h2>
    <table>
      <tr><td>Flights</td><td>TP1235 out, TP1234 back, reference QK4M2X</td></tr>
      <tr><td>Hotel</td><td>Hotel Alecrim, HTL-88213, +351 21 340 0118</td></tr>
      <tr><td>Travel insurance</td><td>Policy TI-2026-3319, claims +44 20 7946 0118</td></tr>
      <tr><td>Emergency contact</td><td>A. Boland, +44 7700 900 118</td></tr>
    </table>
  </section>

  <p class="warn">
    Carry a printed copy. Airline apps require a working data connection and roaming at
    an airport is exactly where it fails. The booking reference above is what a desk
    agent needs; everything else on this page is for you.
  </p>
</body>
</html>

The layout decision worth understanding

Each day carries break-inside: avoid. It is the one structural rule that matters here, because a day split across a page break puts the morning on one side and the evening on the other, and this document is read while walking.

The mistake people make adapting it

Recording times without saying which timezone they are in. It is fine on a domestic trip and it causes a missed flight on an international one. Either state the zone on every time or state once, prominently, that all times are local to where you will be standing.

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.

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": "A4" }
  }' \
  --output itinerary.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 travel itinerary 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.

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