---
name: a4-print-path
description: Two non-obvious constraints in the A4 report print path — the print-root must be a direct body child, and flushSync (not rAF) must precede window.print()
metadata:
type: project
---
Two constraints in `frontend/src/components/ReportEditor/a4/print/` that are easy to
silently break and whose failure mode is a blank or wrong printed page.
**1. `.print-root` must sit on the element appended directly to `
`.**
`print.css` hides the app with `body > *:not(.print-root)` — a CHILD combinator. The app
mounts into ``, itself a direct body child, so the print container is its
sibling. If the class lived only on `PrintDocument`'s inner div, the appended container
would match the hiding rule and print a blank page.
**Why:** the selector is the entire mechanism for hiding the editor during print; there is
no other switch.
**How to apply:** when changing how the print container mounts, keep the class on the
container itself. `printReport.js` sets it; `PrintDocument` repeats it for the standalone
case.
**2. `flushSync` — never `requestAnimationFrame` — before `window.print()`.**
`window.print()` reads the DOM synchronously while React 18 commits asynchronously, so an
unflushed render prints an empty container. rAF was the first fix tried and is wrong: it
does not fire in a background or hidden tab, so a print click would hang instead of
printing.
**Why:** discovered when tests showed `window.print` never being reached behind a
double-rAF await; the background-tab case is the production version of the same bug.
**How to apply:** any new print entry point wraps its `root.render` in `flushSync` from
`react-dom`.
Related: `.a4-print-page` is deliberately NOT `.a4-page` — `A4Canvas.css` already owns
`.a4-page` for the on-screen editor canvas, and both stylesheets load together.