Skip to main content
Full release notes live in the repo’s CHANGELOG.md: one entry per version, covering the engine, every npm package, the Python and Go SDKs, and the VS Code extension.

Recent highlights

  • 0.28.0: text measured and justified the way it is drawn. Content-sized text boxes (flex items, table columns) hold the shaped line they are sized for, so kerned words no longer split mid-word; justified text is justified in registered fonts too, styled runs no longer overlap when justified, and a line ending with a forced break is left unjustified as CSS specifies; Korean documents serialize in milliseconds instead of seconds. Addresses issues #181, #182 and #186. Some of these move existing documents; the changelog lists them.
  • 0.27.0: text that survives copy and paste. Combining marks and shaped clusters in Arabic, Hebrew, Devanagari and Latin extract as their source text in PDF.js and Poppler, while staying valid PDF/UA and PDF/A; registered emoji fonts work as fallbacks; whitespace a font cannot encode, such as the narrow space in French amounts, no longer prints ”?”; and styled right-to-left text places numbers and Latin words where Chrome does. Addresses issues #170, #171 and #175, with fixes contributed by @amruthpillai. Some of these move existing documents; the changelog lists them.
  • 0.26.0: text is drawn where it is laid out. Registered fonts (including the substitutes every PDF/UA and PDF/A document embeds) keep their kerning, justification and mark placement on the page; right-to-left text reads in the right order, with the HTML dir attribute and CSS direction honoured; ragged-right lines stay inside their boxes; and tagged output stops nesting its marked content, so files are about 5% smaller and inline link text is tagged inside its link. Fixes issues #156 to #162. Several of these move existing documents; the changelog lists them.
  • 0.25.0: flex geometry corrected in four places where the engine measured items by their border box and CSS measures them by their outer box, and an item taller than a fixed-height row now overflows it equally in both directions, as Chrome does.
  • 0.24.0 — a flex row that crosses a page continues as parallel columns on every page it spans, wrapped rows included, instead of laying its children out one after another. A two-column layout stays two columns, and the page it starts on stops being half empty. Also the result of a systematic sweep for values the engine computed and never read: 26 of them. Six behavior changes, called out in the release notes, all of them declarations that were inert and now take effect: max-width/min-width on a plain text block, word-spacing as part of text measurement (lines now break where a browser breaks them), @media evaluated against the page content box, a stretched column painting its band on every page its row crosses, an auto-width block filling its container with its auto margins at zero (CSS 2.1 §10.3.3), and a fixed-height box fragmenting across a page boundary instead of losing its height.
  • 0.23.0 — local HTML → PDF from Python with no system libraries (pip install formepdf[local]; the output is byte-identical to @formepdf/html, CI-enforced, because it is the same Rust engine). box-sizing joins the CSS subset — content-box is the CSS default while the engine’s fixed dimension is the border box, so a padded, bordered height rendered short everywhere since the HTML path shipped. Also: pdfa alone now embeds the fonts-standard substitutes, which is the fix you want if you render PDF/A without also claiming PDF/UA.
  • 0.22.0 — PDF 2.0 output (pdfVersion: "2.0"), PDF/A-4 and A-4f (ISO 19005-4:2020), and PDF/UA-2 (ISO 14289-2:2024), all veraPDF-gated in CI across every level. PDF/UA-2 composes with PDF/A-4 for archival and accessible on PDF 2.0. Note that PDF/A-4 is not an accessibility claim — the a/b/u split is gone. Also align-items: baseline in flex rows, previously parsed and treated as flex-start.
  • 0.21.0 — the thirty-template library ships and gets a generated gallery; flex containers item-ize their inline children (the <span>Label</span><span>$1,234</span> space-between row renders as two spread items, not one merged line); flex-grow/flex-shrink/flex: <n> join the HTML subset; characters no font covers report a render defect: naming the character and the remedy instead of silently printing ”?”; auditContent reaches JSX callers through @formepdf/core. Behavior changes, called out in the release notes: absolutely positioned children of a page-spanning parent anchor to the first fragment (was last, spec-incorrect); non-WinAnsi characters in styled runs reach the builtin Noto fallback; the sequential-split warning fires only on genuinely sequential outcomes and names the row; named-page documents drop trailing blank pages; margin-box decoration renders seamlessly.
  • 0.20.1 — RenderHtmlResult.passes is now returned on every target and path (it was declared but undefined on the browser/worker entries and every renderHtmlWithLayout); result objects are built in one shared place and the declared-type-vs-runtime shape is asserted per target in the real runtime. Output is byte-identical to 0.20.0.
  • 0.20.0 — the corpus campaign closes: of the 15 production templates, 14 render correctly, 1 degrades legibly with its cause named in warnings, 0 broken (what the last four taught us). New in the HTML path: attribute selectors (all seven operators + the i flag), CSS tables on divs (the equal-height-columns idiom), rowspan column occupancy, body { overflow-x: hidden } as a page-level clip. Three behavior changes, called out in the release notes: half-leading (every text baseline sits half the leading lower in its line box, per the CSS line box model — line boxes and page breaks unchanged), position: fixed renders as position: absolute (anchored on the page where it occurs, warned), and @media width measures the page box per Media Queries L4 (A4 = 794 CSS px).
  • 0.19.0 — the real-template campaign: floats as column rows, Chrome-matched image sizing, table-section fixes (tfoot/thead/display:none), and the measure/layout agreement gate that closed six phantom-space bugs — measured against 15 production templates from GitHub: 11 render correctly, 4 degrade legibly with named warnings, 0 broken (the full story). One behavior change: bottom/right absolute offsets now anchor the margin edge per CSS — bottom/right-anchored elements with margins sit closer to the top-left, the spec-correct position.
  • 0.18.0 — PDF/A-3 (3b/3u/3a) and Factur-X/ZUGFeRD e-invoice containers: one render call produces the human-readable invoice PDF and embeds your EN 16931 XML as a conformant associated file, CI-validated by veraPDF and Mustangproject. Docs. Also: automatic table layout (banner-row tables no longer collapse — found by a 15-template real-world audit), a new render-defect warning channel, and warning dedup. Two corrections: embedData under PDF/A-2 now errors by name (such files were never valid PDF/A-2), and tables relying on the old first-row column inference re-render correctly.
  • 0.17.0 — CSS Paged Media page selection: @page :left/:right and named pages (@page <name> + the page property) in the HTML path; CSS Grid through the HTML mapper; page-number placeholders no longer switch fonts (custom-font footers stay PDF/A-eligible); ~2× fewer allocations in large-document layout.
  • 0.16.0 — PDF/A-2 conformance (levels 2b, 2u, 2a), veraPDF-verified in CI, composing with PDF/UA-1. Includes a correction: pdfa output from earlier versions was not valid PDF/A — re-render guidance here.
  • 0.15.0 — Vue 3 adapter, @formepdf/fonts-standard, PDF/UA-1 verification as a veraPDF CI gate, and browser/Workers builds of the HTML engine.
  • 0.14.0 — the HTML input path: @formepdf/html, print CSS with @page, margin boxes, and page counters. Docs.
  • 0.13.0 — bookmark outline fixes; the VS Code extension joined the shared version line.
All packages share one version number — @formepdf/react@0.16.0 and forme-pdf@0.16.0 (crates.io) are the same engine.