People and payroll / A4 landscape
Weekly timesheet PDF template
Hours by project and by day across a week, totalled both ways, with an approval signature.
When this document is the right one
Time is recorded for payroll, for client billing, or both. The document is submitted weekly and approved by someone who was not there, so it has to be checkable rather than merely complete.
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.
- Seven day columns and a row per project and task, so the grid totals in both directions and an error in either shows up.
- Weekend columns tinted, because unauthorised weekend hours are the thing an approver is looking for.
- Absence recorded on the same sheet as work, since a week with a day of leave should still total to a full week.
- A summary strip separating standard hours, overtime, absence and billable, which are four different downstream consumers of the same grid.
- A declaration above the signature, because that sentence is what makes the signature mean anything.
The template
A complete file. Doctype, stylesheet, body: paste it into a renderer unchanged and it produces a finished A4 landscape page. Replace the sample data and the styling holds.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Timesheet, week ending 17 May 2026</title>
<style>
/* Landscape, because a week has seven columns and a portrait page squeezes
the project name into two characters. */
@page { size: A4 landscape; margin: 12mm; }
* { box-sizing: border-box; }
body { margin: 0; font: 9pt/1.35 Arial, sans-serif; color: #111; }
header { display: flex; justify-content: space-between; align-items: flex-end;
border-bottom: 2px solid #111; padding-bottom: 4mm; }
h1 { margin: 0; font-size: 15pt; }
.who { display: grid; grid-template-columns: auto auto; gap: 1mm 4mm; font-size: 9pt; }
.who dt { color: #666; }
.who dd { margin: 0; }
table { width: 100%; border-collapse: collapse; margin-top: 5mm; }
thead { display: table-header-group; }
th, td { border: 1px solid #bbb; padding: 2mm; }
th { background: #f2f2f2; font-size: 7.5pt; text-transform: uppercase;
letter-spacing: 0.05em; text-align: center; }
th:first-child, th:nth-child(2) { text-align: left; }
tr { break-inside: avoid; }
td.day { text-align: center; font-variant-numeric: tabular-nums; }
/* Weekend columns tinted so an entry there is noticed at approval rather
than at payroll. */
.weekend { background: #f7f4ee; }
tfoot td { font-weight: 700; background: #f2f2f2; }
.totals-strip { display: grid; grid-template-columns: repeat(5, 1fr); gap: 4mm;
margin-top: 5mm; break-inside: avoid; }
.totals-strip div { border: 1px solid #bbb; padding: 3mm; text-align: center; }
.totals-strip .k { font-size: 7.5pt; text-transform: uppercase; color: #666;
letter-spacing: 0.05em; }
.totals-strip .v { font-size: 14pt; font-weight: 700; font-variant-numeric: tabular-nums;
margin-top: 1mm; }
.declaration { margin-top: 6mm; display: grid; grid-template-columns: 1fr 60mm 60mm;
gap: 8mm; align-items: end; break-inside: avoid; font-size: 8.5pt; }
.declaration .rule { border-top: 1px solid #111; padding-top: 1.5mm; margin-top: 12mm;
color: #666; }
</style>
</head>
<body>
<header>
<div>
<h1>Weekly timesheet</h1>
<div style="margin-top:1.5mm">Kilnworks Studio Ltd</div>
</div>
<dl class="who">
<dt>Employee</dt><dd>S. Whitlock</dd>
<dt>Payroll number</dt><dd>KW-0142</dd>
<dt>Week ending</dt><dd>Sunday 17 May 2026</dd>
<dt>Approver</dt><dd>E. Prentice</dd>
</dl>
</header>
<table>
<thead>
<tr>
<th>Project</th><th>Task</th>
<th>Mon 11</th><th>Tue 12</th><th>Wed 13</th><th>Thu 14</th><th>Fri 15</th>
<th class="weekend">Sat 16</th><th class="weekend">Sun 17</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td>RVH-2026</td><td>Ravenshill range, throwing</td>
<td class="day">7.5</td><td class="day">7.5</td><td class="day">4.0</td>
<td class="day">-</td><td class="day">-</td>
<td class="day weekend">-</td><td class="day weekend">-</td>
<td class="day">19.0</td>
</tr>
<tr>
<td>RVH-2026</td><td>Glaze trials, kiln 2</td>
<td class="day">-</td><td class="day">-</td><td class="day">3.5</td>
<td class="day">7.5</td><td class="day">3.0</td>
<td class="day weekend">-</td><td class="day weekend">-</td>
<td class="day">14.0</td>
</tr>
<tr>
<td>INT-STUDIO</td><td>Kiln maintenance</td>
<td class="day">-</td><td class="day">-</td><td class="day">-</td>
<td class="day">-</td><td class="day">2.0</td>
<td class="day weekend">4.5</td><td class="day weekend">-</td>
<td class="day">6.5</td>
</tr>
<tr>
<td>ABSENCE</td><td>Annual leave</td>
<td class="day">-</td><td class="day">-</td><td class="day">-</td>
<td class="day">-</td><td class="day">2.5</td>
<td class="day weekend">-</td><td class="day weekend">-</td>
<td class="day">2.5</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2">Daily total</td>
<td class="day">7.5</td><td class="day">7.5</td><td class="day">7.5</td>
<td class="day">7.5</td><td class="day">7.5</td>
<td class="day weekend">4.5</td><td class="day weekend">0.0</td>
<td class="day">42.0</td>
</tr>
</tfoot>
</table>
<div class="totals-strip">
<div><div class="k">Standard hours</div><div class="v">35.0</div></div>
<div><div class="k">Overtime 1.5x</div><div class="v">4.5</div></div>
<div><div class="k">Annual leave</div><div class="v">2.5</div></div>
<div><div class="k">Sick</div><div class="v">0.0</div></div>
<div><div class="k">Billable</div><div class="v">33.0</div></div>
</div>
<div class="declaration">
<div>
I confirm that the hours recorded above are a true record of time worked and
that any weekend or overtime hours were authorised in advance.
</div>
<div class="rule">Employee signature and date</div>
<div class="rule">Approved by and date</div>
</div>
</body>
</html>The layout decision worth understanding
Landscape A4. A week has seven columns plus a project name, a task name and a total, and in portrait the project name is squeezed to two characters. Choosing landscape is the difference between a usable grid and an abbreviation exercise.
The mistake people make adapting it
Totalling only across rows and not down columns. A day that should be seven and a half hours and comes to nine and a half is only visible in the column total, and that is the error worth catching before it reaches payroll.
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 timesheet.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 weekly timesheet is a A4 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.
Payslip HTML template with CSS
A statement of pay for one period: gross made of its parts, deductions made of theirs, the net that was actually paid, and the year to date.
Expense report HTML template
An itemised claim for reimbursement: expenses with receipts and business purposes, mileage calculated separately, and a policy note explaining the rules being applied.
Employment offer letter template
A letter offering a role, stating the principal terms in a scannable block, the conditions the offer depends on, and an acceptance section to sign and return.
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.
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.
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.