@formepdf/html renders HTML + print CSS to PDF through the same Rust/WASM engine that renders JSX components. No headless browser, no Chromium cold start.
The subset — the constitution
This is a deliberately documented subset of HTML/CSS, in the spirit of Satori — but page-native. Everything supported is listed below and tested. Everything outside the subset lands in thewarnings list at render time, named, with a remedy where one exists. Nothing fails silently.
Paged media — the point of the whole thing
Elements
Selectors
Properties
CSS Grid is supported as a documented subset (not all of grid): fr/px/auto/minmax tracks, integerrepeat() — including Tailwind’s repeat(N, minmax(0, 1fr)) — gaps, spans, and numeric line placement; named lines, areas, auto-flow, auto-fill/fit, percentage tracks, and negative line numbers warn by name. The full property table lives in the package README — margins with CSS margin collapsing, borders (solid/dashed/dotted with Chrome-matched dash metrics), border-collapse emulation, min/max width constraints (the centered-column idiom works), font fallback chains, text-align: justify with real Knuth-Plass distribution, text-transform, letter-spacing, vertical-align on cells, flexbox, relative/absolute positioning, floats as column rows (float: left/right + clear — consecutive floated siblings form a row, the Bootstrap col-* / left-right header-pair shape; text wrapping alongside a float is not supported and warns — following content renders below), CSS tables on divs (display: table/table-row/table-cell — the equal-height-columns idiom; a single-row one becomes a breakable column row), position: fixed as position: absolute by policy (anchored on the page where it occurs, not repeated per page — margin boxes are the running-content mechanism), and body { overflow-x: hidden } as a page-level clip (how off-viewport-parked sidebars stay invisible).
Notable exclusions, all warned by name: CSS variables, position: sticky, transforms, gradients, @font-face fetching (use options.fonts / --font — see the web-fonts migration recipe).
The warnings contract
@font-face family. If a render is silent, the document used only the subset — and what you got is what the subset defines.