php pdf library · for PHP developers at US cities, counties, school districts and special districts
Your council agenda PDF, read by a screen reader: 1 of 8 checks vs. 8 of 8
Same one-page agenda, scanned live below by the checker on this page. Left: drawn the way FPDF, TCPDF and dompdf draw it by default. Right: written with readystack/tagged-pdf. Under ADA Title II (28 CFR 35.200) the PDFs a city of 50,000+ people posts must meet WCAG 2.1 AA from April 26, 2027.
Untagged agenda (standard-font PHP PDF)
agenda-untagged.pdf
…
Same agenda, tagged by this library
agenda-tagged.pdf
…
Check your own PDF (free, never uploaded)
A fast screen, not a full PDF/UA validator: a file can pass all 8 and still have alt text that says nothing useful. For the full Matterhorn Protocol use PAC or veraPDF.
Your ADA Title II date
| Covered? | |
|---|---|
| New agenda, notice or report posted on or after your date | Yes — 35.200(b) |
| Application or permit form, even if posted earlier, still used to apply | Yes — 35.201(b) does not apply |
| Old PDF posted before your date, no longer used to apply for a service | Excepted — 35.201(b) |
| Bill or statement about one person or account, behind a login | Excepted — 35.201(d) |
Source: 28 CFR 35.104, 35.200, 35.201 on law.cornell.edu, read 2026-09-29. Not legal advice.
Why the free libraries are not enough
FPDF, TCPDF and dompdf are free and print fine, but they write untagged PDFs with unembedded standard fonts. Fixing each file afterwards in Acrobat is repeated for every PDF your app generates, and tonight's export is untagged again. This library fixes the source: the PDF is born tagged, and it throws a named exception instead of saving an inaccessible file.
composer require readystack/tagged-pdf
$pdf = new TaggedPdf('City Council Regular Meeting Agenda, October 14, 2026', 'en-US', $regular, $bold);
$pdf->heading(1, 'City Council Regular Meeting Agenda')
->paragraph('Tuesday, October 14, 2026, 6:00 p.m., Council Chambers.')
->table(['Fund', 'Department', 'Change'], $rows)
->image('chart.jpg', 'Bar chart of capital spending by quarter.', 300)
->save('agenda.pdf'); // 8 of 8 checks pass
PHP 8.1+, zero dependencies. Shared hosting without Composer: run composer require locally and upload the vendor/ folder. You need one .ttf font whose licence allows embedding (DejaVu Sans, Noto Sans, Liberation Sans).
Questions
What does readystack/tagged-pdf do?
It is a PHP PDF library that writes tagged PDFs: every heading, paragraph, list, table cell and image sits in a structure tree a screen reader can navigate. It embeds a subset of your TrueType font, sets the document language and title, marks headers and footers as artifacts, builds bookmarks from headings and adds the PDF/UA-1 identifier. Our sample agenda passes 8 of 8 checks.
Who is it for?
PHP developers at US cities, counties, school districts and special districts, and the vendors who build their portals, whose apps generate agendas, public notices, permits and application forms as PDF. Under 28 CFR 35.200 those PDFs must meet WCAG 2.1 AA from April 26, 2027 (50,000 people or more) or April 26, 2028 (smaller entities and special districts).
Why not keep FPDF, TCPDF or dompdf?
They are free and fine for printing, but they write untagged PDFs: no structure tree, no language, no table headers, and standard fonts that are not embedded. Our one-page agenda drawn that way scores 1 of 8 in the checker. Fixing each file afterwards in Acrobat Pro is manual work per document, and tomorrow's generated PDF is untagged again.
What is free?
The web checker is free in your browser: open any PDF and see which of the 8 checks it passes or fails, with the reason, plus your Title II compliance date from your total population. Nothing is uploaded. The paid part is the PHP library that makes your application write PDFs that pass, every time, on your own server.
What does it cost compared with the alternatives?
$60 once, not a subscription, for one organisation and any number of its projects. The free libraries cost nothing but leave every generated PDF untagged, so each one needs manual remediation after it is made. This library fixes the source: the PDF is born tagged, and it throws a named exception instead of saving an inaccessible file.
