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

    …

      Full version — $60 once The PHP library that makes every PDF your app writes pass all 8 · one payment, not a subscription · check your own PDF free first, below

      Check your own PDF (free, never uploaded)

      Open the last PDF your site generated: an agenda, notice, permit or application form.

      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

      PDFCovered?
      New agenda, notice or report posted on or after your dateYes — 35.200(b)
      Application or permit form, even if posted earlier, still used to applyYes — 35.201(b) does not apply
      Old PDF posted before your date, no longer used to apply for a serviceExcepted — 35.201(b)
      Bill or statement about one person or account, behind a loginExcepted — 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.

      Get the complete version $60

      This page is the working piece. The full pack has everything below.

      Council agendas, notices and permit forms your PHP app writes pass 8 of 8 accessibility checks, before the April 26, 2027 Title II date

      28 CFR 35.200 (law.cornell.edu, 2026-09-29): PDFs a public entity of 50,000+ people posts must meet WCAG 2.1 AA from April 26, 2027; under 50,000 and special districts from April 26, 2028.

      Buy the full version — $60
      ENDEJAESPT

      Find a tool

      · ReadyStack

      Worked example

      Real numbers from this tool, line by line.

      PHP PDF library for accessible tagged PDFs (ADA Title II)

      A city clerk's office runs a PHP app that turns every council agenda, public notice and permit form into a PDF. The PDFs print fine. A screen reader gets a flat stream of words with no headings, no table headers and no document language.

      The date that makes this urgent is in 28 CFR 35.200. A state or local government with a total population of 50,000 or more must make the web content it provides meet WCAG 2.1 Level A and AA from April 26, 2027. Under 50,000, and every special district government, from April 26, 2028. Section 35.104 names PDFs as conventional electronic documents, so the agenda your app posts after that date is in scope.

      Two exceptions matter for generated files. Under 35.201(b) a PDF posted before your date is excepted unless it is still used to apply for, gain access to or participate in a service, so an old permit application that is still live is not excepted. Under 35.201(d) a document about one person, their property or account that is password-protected or otherwise secured is excepted, such as a utility statement behind a login.

      We drew the same one-page agenda twice and scanned both with the same 8 checks. The first was drawn the way FPDF, TCPDF and dompdf draw by default: standard Helvetica, not embedded, no tags. It passes 1 of 8. The only pass is alt text, because it has no figures at all. The second was written with readystack/tagged-pdf and passes 8 of 8: tagged, structure tree, document language, title shown instead of file name, PDF/UA identifier, every font embedded, alt text on every figure, and structure tab order on every page.

      The library works at the source. heading(), paragraph(), bulletList(), table() and image() each create a structure element and put every line in marked content linked to it. Page headers, footers, rules, the table grid and table headers repeated after a page break are tagged as artifacts, so they are not read twice. The font you pass is embedded as a subset with a ToUnicode map, and bookmarks are built from your headings.

      It also refuses to write a file that fails. An empty title throws MissingTitleException. "english" instead of en-US throws InvalidLanguageTagException. H1 followed by H3 throws HeadingLevelException. An image with empty alt text throws MissingAltTextException, and a table without a header row throws MissingTableHeaderException. There are 10 named exceptions, and all of them extend TaggedPdfException.

      The same 8 checks ship as Preflight, a PHP class you can run on any PDF, including ones from other libraries and files with compressed object streams, and as a CLI script that exits with code 1 so it can gate a CI job. It is a fast screen, not a full PDF/UA validator, so run PAC or veraPDF on a sample too.

      The web checker is free and runs in your browser, so your file is never uploaded. Open the last PDF your site generated and see which checks fail, then enter your total population to get your date. If it fails, composer require readystack/tagged-pdf, keep your data code, and replace the drawing calls.

      15 seconds — what it actually does

      Questions people ask

      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.

      Ask about this tool

      One question, answered by the person who built it. Your email only if you want the answer sent.